package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.ConfigConstant;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.SizeConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.PaasProcessDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.constant.EsNormalConstant;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.model.PaasFormDataEsModel;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DefaultTypeEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.FundAccountFlowTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.PaySheetTypeEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.enums.SheetTypeEnum;
import com.xbongbong.paas.enums.UnitEnum;
import com.xbongbong.paas.field.DefaultAttrPoJo;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.FormDataValidateDataHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.team.TeamUserHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.log.pojo.InfoArrPojo;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.model.PaasProcessDataModel;
import com.xbongbong.paas.model.PaasProcessTemplateModel;
import com.xbongbong.paas.pojo.AddMuchFieldPojo;
import com.xbongbong.paas.field.DefaultAttrPoJo;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.pojo.AttrValuePojo;
import com.xbongbong.paas.pojo.FieldAttrEntityForImport;
import com.xbongbong.paas.pojo.FormTitlePoJo;
import com.xbongbong.paas.pojo.IdNamePojo;
import com.xbongbong.paas.pojo.SummaryDataPoJo;
import com.xbongbong.paas.pojo.dto.AddBatchDTO;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataDeleteBatchDTO;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.dto.FormDataUpdateDTO;
import com.xbongbong.paas.pojo.dto.ImportFormDataDTO;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.pojo.dto.StartProcessDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.imports.CellTitlePojo;
import com.xbongbong.paas.pojo.imports.CellValuePojo;
import com.xbongbong.paas.pojo.imports.RowGroupPojo;
import com.xbongbong.paas.pojo.vo.FormDataAddVO;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsListVO;
import com.xbongbong.paas.pojo.vo.StartProcessVO;
import com.xbongbong.paas.service.PaasFormExplainService;
import com.xbongbong.paas.service.WorkflowOperatorDataService;
import com.xbongbong.paas.service.team.TeamDataHelp;
import com.xbongbong.paas.service.workflow.WorkflowDataService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.applist.pojo.AppListPojo;
import com.xbongbong.pro.applist.pojo.vo.ListAppVO;
import com.xbongbong.pro.businessdata.pojo.dto.FormatExplainDTO;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.SymbolConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.ContractErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.InvoiceErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.PayErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.PaymentErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.TemplateErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.UserTeamErrorCodeEnum;
import com.xbongbong.pro.formdata.pojo.AfterSavePojo;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainInLinkItemDTO;
import com.xbongbong.pro.listbatch.pojo.dto.AddLabelDTO;
import com.xbongbong.pro.message.constant.PayPlanPushConstant;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.help.PushHelper;
import com.xbongbong.pro.message.pojo.PushRefTypePojo;
import com.xbongbong.pro.message.pojo.dto.MessageRabbitMqDTO;
import com.xbongbong.pro.paymentsheet.pojo.dto.PaymentSheetSaveDTO;
import com.xbongbong.pro.payplansheet.pojo.dto.PayPlanSheetDeleteBatchDTO;
import com.xbongbong.pro.payplansheet.pojo.dto.PayPlanSheetInsertBatchDTO;
import com.xbongbong.pro.payplansheet.pojo.dto.PayPlanSheetInsertDTO;
import com.xbongbong.pro.payplansheet.pojo.dto.PaySheetEditAttrUpdateDTO;
import com.xbongbong.pro.payplansheet.pojo.dto.PaySheetUpdateBatchDTO;
import com.xbongbong.pro.payplansheet.pojo.dto.PaySheetUpdateDTO;
import com.xbongbong.pro.payplansheet.pojo.dto.batch.PayPlanSheetDTO;
import com.xbongbong.pro.payplansheet.pojo.dto.batch.PayPlanSheetInsertBatchByPurchaseDTO;
import com.xbongbong.pro.payplansheet.pojo.dto.batch.PayPlanSheetUpdateBatchMuchFieldDTO;
import com.xbongbong.pro.payplansheet.pojo.vo.PayPlanSheetDeleteBatchVO;
import com.xbongbong.pro.payplansheet.pojo.vo.PayPlanSheetInsertBatchVO;
import com.xbongbong.pro.payplansheet.pojo.vo.PaySheetUpdateBatchVO;
import com.xbongbong.pro.payplansheet.pojo.vo.batch.PayPlanSheetAmountVO;
import com.xbongbong.pro.payplansheet.pojo.vo.batch.PayPlanSheetInsertBatchByPurchaseVO;
import com.xbongbong.pro.payplansheet.pojo.vo.batch.PayPlanSheetUpdateBatchMuchFieldVO;
import com.xbongbong.pro.rabbitmq.producer.BaseProducer;
import com.xbongbong.pro.service.toolbox.elasticsearch.help.ProEsHelper;
import com.xbongbong.pro.service.toolbox.statistic.help.FormHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.SystemChartHelp;
import com.xbongbong.pro.sheet.pojo.AmountDetailGetPojo;
import com.xbongbong.pro.sheet.pojo.SheetAttrPojo;
import com.xbongbong.pro.sheet.pojo.dto.SheetAmountDetailGetDTO;
import com.xbongbong.pro.sheet.pojo.dto.SheetDeleteHandleRelateDTO;
import com.xbongbong.pro.sheet.pojo.dto.SheetSaveDTO;
import com.xbongbong.pro.sheet.pojo.vo.SheetAmountDetailGetVO;
import com.xbongbong.pro.team.TeamAfterVerifyDTO;
import com.xbongbong.pro.thread.ThreadPoolBeanConfig;
import com.xbongbong.pro.user.pojo.ReturnUserAndDepartmentPojo;
import com.xbongbong.process.operate.ProcessStartHelp;
import com.xbongbong.saas.analytical.impl.PayPlanSheetValidateAnalyticalServiceImpl;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.FundAccountFlowEntity;
import com.xbongbong.saas.domain.entity.PayBalanceEntity;
import com.xbongbong.saas.domain.entity.PayPlanSheetUserEntity;
import com.xbongbong.saas.domain.entity.UserTeamEntity;
import com.xbongbong.saas.domain.entity.ext.PayPlanSheetEntityExt;
import com.xbongbong.saas.enums.LinkAddOperationFlagEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.SheetAloneEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.PayPlanEnum;
import com.xbongbong.saas.enums.business.PaySheetEnum;
import com.xbongbong.saas.enums.business.PaymentEnum;
import com.xbongbong.saas.enums.business.PurchaseEnum;
import com.xbongbong.saas.enums.business.PurchaseInvoiceEnum;
import com.xbongbong.saas.enums.business.SupplierEnum;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.help.ImportHelper;
import com.xbongbong.saas.help.LogHandleHelp;
import com.xbongbong.saas.help.SaasDataInitHelp;
import com.xbongbong.saas.help.SaasDeleteHelp;
import com.xbongbong.saas.help.SaasListHelp;
import com.xbongbong.saas.help.SaasPayPlanHelper;
import com.xbongbong.saas.help.SaasPaySheetHelper;
import com.xbongbong.saas.help.SaasRefundHelper;
import com.xbongbong.saas.help.SaasSaveHelp;
import com.xbongbong.saas.help.SaasUpdateHelp;
import com.xbongbong.saas.help.fund.PayPlanSheetHelp;
import com.xbongbong.saas.help.workflow.PayAndPaymentSheetHelp;
import com.xbongbong.saas.help.workflow.PurchaseHelp;
import com.xbongbong.saas.model.FundAccountFlowModel;
import com.xbongbong.saas.model.PayBalanceModel;
import com.xbongbong.saas.model.PayPlanModel;
import com.xbongbong.saas.model.PayPlanSheetModel;
import com.xbongbong.saas.model.PayPlanSheetUserModel;
import com.xbongbong.saas.model.PurchaseModel;
import com.xbongbong.saas.service.FundAccountFlowService;
import com.xbongbong.saas.service.FundAccountService;
import com.xbongbong.saas.service.PayBalanceService;
import com.xbongbong.saas.service.PayPlanService;
import com.xbongbong.saas.service.PayPlanSheetService;
import com.xbongbong.saas.service.PurchaseInvoiceService;
import com.xbongbong.saas.service.PurchaseService;
import com.xbongbong.saas.service.ReturnedPurchaseService;
import com.xbongbong.saas.service.UserTeamService;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import com.xbongbong.saas.service.toolbox.help.SaasSaveHelper;
import com.xbongbong.saas.service.toolbox.help.UserTeamHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.UserModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static java.lang.String.format;
import static java.lang.String.join;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;


/**
 * 付款单业务实现
 *
 * @author feng.zheng
 * @version v1.0
 * @date 2019/1/22 15:10
 * @since v1.0
 */
@Service("payPlanSheetService")
public class PayPlanSheetServiceImpl implements PayPlanSheetService {
    private static final Logger LOG = LoggerFactory.getLogger(PayPlanSheetServiceImpl.class);

    @Resource
    private PayPlanSheetModel payPlanSheetModel;
    @Resource
    private SaasUpdateHelp saasUpdateHelp;
    @Resource
    private UserModel userModel;
    @Resource
    private PayPlanModel payPlanModel;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private PaasProcessTemplateModel paasProcessTemplateModel;
    @Resource
    private ProcessStartHelp processStartHelp;
    @Resource
    private SaasSaveHelp saasSaveHelp;
    @Resource
    private SaasSaveHelper saasSaveHelper;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private SystemChartHelp systemChartHelp;
    @Resource
    private EsHelper esHelper;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private FundHelp fundHelp;
    @Resource
    private FormHelp formHelp;
    @Resource
    private PaasFormDataEsModel paasFormDataEsModel;
    @Resource
    private FormDataValidateDataHelp formDataValidateDataHelp;
    @Resource
    private PayBalanceModel payBalanceModel;
    @Resource
    private ProEsHelper proEsHelper;
    @Resource
    private PurchaseModel purchaseModel;
    @Resource
    private PayPlanService payPlanService;
    @Resource
    private PurchaseService purchaseService;
    @Resource
    private PayBalanceService payBalanceService;
    @Resource
    private PushHelper pushHelper;
    @Resource
    private BaseProducer baseProducer;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private SaasListHelp saasListHelp;
    @Resource
    private ReturnedPurchaseService returnedPurchaseService;
    @Resource
    private FundAccountService fundAccountService;
    @Resource
    private PaasProcessDataModel paasProcessDataModel;
    @Resource
    private PurchaseInvoiceService purchaseInvoiceService;
    @Resource
    private FundAccountFlowModel fundAccountFlowModel;
    @Resource
    private FundAccountFlowService fundAccountFlowService;
    @Resource
    private ImportHelper importHelper;
    @Resource
    private PayPlanSheetUserModel payPlanSheetUserModel;
    @Resource
    private UserTeamService userTeamService;
    @Resource
    private ThreadPoolBeanConfig threadPoolBeanConfig;
    @Resource
    private PayPlanSheetHelp payPlanSheetHelp;
    @Resource
    private PaasFormExplainService paasFormExplainService;
    @Resource
    private LogHelp logHelp;
    @Resource
    private LogHandleHelp logHandleHelp;
    @Resource
    private PayPlanSheetValidateAnalyticalServiceImpl payPlanSheetAnalyticalService;
    @Resource
    private PayAndPaymentSheetHelp payAndPaymentSheetHelp;
    @Resource
    private SaasPaySheetHelper saasPaySheetHelper;
    @Resource
    private SaasPayPlanHelper saasPayPlanHelper;
    @Resource
    private PurchaseHelp purchaseHelp;
    @Resource
    private WorkflowOperatorDataService workflowOperatorDataService;
    @Resource
    private WorkflowDataService workflowDataService;
    @Resource
    private SaasRefundHelper saasRefundHelper;
    @Resource
    private UserTeamHelp userTeamHelp;
    @Resource
    private TeamDataHelp teamDataHelp;
    @Resource
    private TeamUserHelp teamUserHelp;

    @Override
    public PayPlanSheetInsertBatchVO insertBatch(PayPlanSheetInsertBatchDTO payPlanSheetInsertBatchDTO, String processCreatorId) throws XbbException{
        PayPlanSheetInsertBatchVO payPlanSheetInsertBatchVO = new PayPlanSheetInsertBatchVO();
        List<PayPlanSheetInsertDTO> paymentSheetDTOList = payPlanSheetInsertBatchDTO.getPayPlanSheetList();
        String corpid = payPlanSheetInsertBatchDTO.getCorpid();
        List<PayPlanSheetEntityExt> paymentSheetList = new ArrayList<>();

        try {
            PaasFormEntityExt paasFormEntityExt = paasFormModel.getByBusinessType(XbbRefTypeEnum.PAY_SHEET.getCode(), payPlanSheetInsertBatchDTO.getCorpid());
            long now = DateTimeUtil.getInt();
            if (!paymentSheetDTOList.isEmpty()) {
                for (PayPlanSheetInsertDTO item :paymentSheetDTOList){
                    PayPlanSheetEntityExt payPlanSheetEntityExt = new PayPlanSheetEntityExt();
                    payPlanSheetEntityExt.setDepartmentId(1L);
                    payPlanSheetEntityExt.setFlowStatus(0);
                    payPlanSheetEntityExt.setOwnerId(payPlanSheetInsertBatchDTO.getUserId());
                    BeanUtil.copyProperties(item, payPlanSheetEntityExt);
                    payPlanSheetEntityExt.setCorpid(corpid);
                    if (processCreatorId == null) {
                        payPlanSheetEntityExt.setCreatorId(payPlanSheetInsertBatchDTO.getUserId());
                    } else {
                        payPlanSheetEntityExt.setCreatorId(processCreatorId);
                    }
                    try {
                        payPlanSheetEntityExt.setSerialNo(FastJsonHelper.getStringFromFormData(item.getData(), PaySheetEnum.PAY_PLAN_NO.getAttr()));
                    } catch (XbbException e){
                    }
                    payPlanSheetEntityExt.setAddTime(now);
                    payPlanSheetEntityExt.setUpdateTime(now);
                    payPlanSheetEntityExt.setFormId(paasFormEntityExt.getId());
                    JSONObject dataList = item.getData();
                    payPlanSheetEntityExt.setUuid(UUID.randomUUID().toString());
                    payPlanSheetEntityExt.setAlone(SheetAloneEnum.NORMAL.getCode());
                    for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPayPlanSheet().entrySet()){
                        SaasDataInitHelp.antDataSet(dataList,entry.getKey(),entry.getValue());
                    }
                    payPlanSheetEntityExt.setData(dataList);
                    paymentSheetList.add(payPlanSheetEntityExt);
                }

                List<PayPlanSheetEntityExt> payPlanSheetEntityExtList = payPlanSheetModel.insertBatch(paymentSheetList);
                List<FundAccountFlowEntity> fundAccountFlowEntities = new ArrayList<>();
                Map<Long, Double> fundAccountToAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByBusinessType(XbbRefTypeEnum.PAY_SHEET.getCode(), corpid);
                Map<String, FieldAttrEntity> explainMap = paasFormExplainEntity == null ? null : ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), PaySheetEnum.REAL_PAY_TIME.getAttr());
                for (PayPlanSheetEntityExt payPlanSheetEntityExt : payPlanSheetEntityExtList) {
                    JSONObject dataList = payPlanSheetEntityExt.getData();
                    String sheetType = FastJsonHelper.getStringFromFormData(dataList, PaySheetEnum.PAY_SHEET_TYPE.getAttr());
                    if (!Objects.equals(sheetType, PaySheetTypeEnum.BAD_PAY.getCode()) && !Objects.equals(sheetType, PaySheetTypeEnum.WRITE_OFF_PREPAY.getCode())) {
                        Long accountId = FastJsonHelper.getLongOrDefaultFromFormData(dataList, PaySheetEnum.FUND_ACCOUNT.getAttr(), 0L);
                        Long sheetTime = fundHelp.getSheetTime4FundFlow(dataList, PaySheetEnum.REAL_PAY_TIME.getAttr(), explainMap, now);
                        Double sheetAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.AMOUNT.getAttr(), 0D);
                        //账户余额变动 付款取反
                        sheetAmount = Arith.mul(sheetAmount, -1);
                        fundAccountToAmountMap.merge(accountId, sheetAmount, Arith::add);
                        //流水表日志记录
                        FundAccountFlowEntity fundAccountFlowEntity = new FundAccountFlowEntity(corpid, now, payPlanSheetEntityExt.getCreatorId(), FundAccountFlowTypeEnum.PAY_SHEET.getCode(), payPlanSheetEntityExt.getId(), accountId, sheetTime, sheetAmount);
                        fundAccountFlowEntities.add(fundAccountFlowEntity);
                    }
                }
                if (fundAccountFlowEntities.size() > 0) {
                    fundAccountFlowModel.insertBatch(fundAccountFlowEntities);
                }
                if (fundAccountToAmountMap.size() > 0) {
                    fundAccountService.saveBatchByPaymentSheetOrPaySheet(fundAccountToAmountMap);
                }
                List<Long> paymentIdList = new ArrayList<>();
                List<Long> purchaseIdIn = new ArrayList<>();
                Map<Long,List<Long>> idAndContractIdMap = new HashMap<>(payPlanSheetEntityExtList.size());
                List<Long> purchaseIds = new ArrayList<>();
                for (PayPlanSheetEntityExt paymentEntityExt : payPlanSheetEntityExtList){
                    paymentIdList.add(paymentEntityExt.getId());
                    JSONObject data =  paymentEntityExt.getData();
                    JSONArray purchaseIdArr  = FastJsonHelper.getJsonArrFromFormData(data,PaySheetEnum.LINK_PURCHASE.getAttr());
                    for ( Object purchaseId : purchaseIdArr ) {
                        if ( Objects.nonNull(purchaseId) ) {
                            Long purchaseIdIdLong = Long.valueOf(purchaseId.toString());
                            purchaseIdIn.add(purchaseIdIdLong);
                            purchaseIds.add(purchaseIdIdLong);
                        }
                    }
                    idAndContractIdMap.put(paymentEntityExt.getId(),purchaseIds);
                }
                if (true){
                    List<ReturnUserAndDepartmentPojo> ownerId = payPlanSheetInsertBatchDTO.getOwnerId() == null ? new ArrayList<>() : payPlanSheetInsertBatchDTO.getOwnerId();
                    List<ReturnUserAndDepartmentPojo> coUserId = payPlanSheetInsertBatchDTO.getCoUserId() == null ? new ArrayList<>() : payPlanSheetInsertBatchDTO.getCoUserId();
                    // 审批数据和导入数据没传userName,兼容一下
                    commonHelp.setUserName4UserPojo(corpid, ownerId, coUserId);
                    List<PayPlanSheetUserEntity> paySheetUserEntityList = new ArrayList<>();
                    for (Long paymentId : paymentIdList) {
                        for (ReturnUserAndDepartmentPojo entity : ownerId) {
                            getPayPlanSheetSheetUserTeam( paySheetUserEntityList, paymentId, entity, BasicConstant.MAIN_USER, corpid);
                        }
                        for (ReturnUserAndDepartmentPojo entity : coUserId) {
                            getPayPlanSheetSheetUserTeam( paySheetUserEntityList, paymentId, entity, BasicConstant.COOP_USER, corpid);
                        }
                    }
                    if (!paySheetUserEntityList.isEmpty()){
                        payPlanSheetUserModel.insertBatch(paySheetUserEntityList);
                    }
                }
            }
        } catch (Exception e) {
            LOG.error("payPlanSheetServiceImpl.insertBatch批量添加付款单出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        if (!paymentSheetDTOList.isEmpty()) {
            // 记录日志
            List<String> addBatchSerialNoList= new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            paymentSheetList.forEach(entityExt -> addBatchSerialNoList.add(entityExt.getSerialNo()));
            String addBatchSerialNoStr = StringUtils.join(addBatchSerialNoList, "，");
            String userId = payPlanSheetInsertBatchDTO.getUserId();
            String creatName = "";
            if(processCreatorId != null){
                // 走审批时获取创建人id
                UserEntity user = userModel.getByKeyIngoreDel(processCreatorId, corpid);
                creatName = user.getName();
            }
            String loginUserName = processCreatorId == null ? payPlanSheetInsertBatchDTO.getLoginUserName() : creatName;
            userId = processCreatorId == null ? userId : processCreatorId;
            if(paymentSheetList.size() > 1){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_BATCH_ADD_FORM_DETAIL), loginUserName, XbbRefTypeEnum.PAY_SHEET.getName(), paymentSheetList.size());
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(PaySheetEnum.PAY_PLAN_NO.getAttrName());
                infoArrPojo.setContent(addBatchSerialNoStr);
                infoArrPojoList.add(infoArrPojo);
                mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, loginUserName, OperateModuleTypeEnum.PayManage, OperateTypeEnum.NEW,
                        "", "", memo, payPlanSheetInsertBatchDTO.getHttpHeader());
            } else if (Objects.equals(paymentSheetList.size(), 1)){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_ADD_WORK), loginUserName, XbbRefTypeEnum.PAY_SHEET.getName(), addBatchSerialNoStr);
                mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.PayManage, OperateTypeEnum.NEW,
                        paymentSheetList.get(0).getId().toString(), addBatchSerialNoStr, memo, payPlanSheetInsertBatchDTO.getHttpHeader());
            }
        }

        return payPlanSheetInsertBatchVO;
    }

    @Override
    public FormDataAddVO add(PayPlanSheetInsertDTO payPlanSheetInsertDTO, PaasFormDataEntity paasFormDataEntity, PaasFormEntityExt paasFormEntityExt) throws XbbException {
        FormDataAddVO formDataAddVO = new FormDataAddVO();
        JSONObject dataList = paasFormDataEntity.getData();
        Integer businessType = payPlanSheetInsertDTO.getBusinessType();
        SheetTypeEnum sheetTypeEnum = SheetTypeEnum.getByBusinessType(businessType);
        Long returnedPurchaseId = dataList.getLong(PaasConstant.RETURNED_PURCHASE_ID);
        //删除不在mapping中的字段  兼容老数据
        fundHelp.removeNotInMapping(dataList);
        fundHelp.removeNotInMapping(payPlanSheetInsertDTO.getDataList());
        //明细
        fundHelp.removeNotInMapping4Array(payPlanSheetInsertDTO.getAmountDetail());
        //校验付款单金额不能为0
        saasSaveHelper.checkSheetAmount(sheetTypeEnum, dataList);
        switch (sheetTypeEnum) {
            case WRITE_OFF_PAY:
            case WRITE_OFF_PREPAY:
                //已核销、预付款核销
                writeOffSave(sheetTypeEnum, payPlanSheetInsertDTO, paasFormDataEntity, paasFormEntityExt);
                break;
            case RED_WRITE_OFF_PAY:
            case RED_WRITE_OFF_PREPAY:
                //红冲已核销、红冲预付款核销
                redSave(sheetTypeEnum, payPlanSheetInsertDTO, paasFormDataEntity, paasFormEntityExt);
                break;
            case PREPAY:
            case RED_PREPAY:
                //预付款、红冲预付款余额
                prepaySave(sheetTypeEnum, payPlanSheetInsertDTO, paasFormDataEntity, paasFormEntityExt);
                break;
            case BAD_PAY:
                //坏账
                badSave(sheetTypeEnum, payPlanSheetInsertDTO, paasFormDataEntity, paasFormEntityExt);
                break;
            default:
                break;
        }
        if (returnedPurchaseId != null && Objects.equals(paasFormEntityExt.getIsProcessForm(), BasicConstant.ONE)) {
            saasRefundHelper.updateReturnedPurchasePaySheetId(returnedPurchaseId, paasFormDataEntity, payPlanSheetInsertDTO.getCorpid());
        }
        formDataAddVO.setMsg(I18nMessageUtil.getMessage(MessageConstant.FORM_ADD_RETURN_MSG));
        formDataAddVO.setCode(PaasConstant.FORM_ADD_RETURN_CODE);
        return formDataAddVO;
    }

    @Override
    public void formatAddExplain(FormatExplainDTO formatExplainDTO) throws XbbException {
        List<FieldAttrEntity> explainList = formatExplainDTO.getExplainList();
        for (FieldAttrEntity fieldAttrEntity : explainList) {
            if (Objects.equals(fieldAttrEntity.getAttr(), PaySheetEnum.REAL_PAY_TIME.getAttr())) {
                DefaultAttrPoJo defaultAttrPoJo = fieldAttrEntity.getDefaultAttr();
                if (StringUtil.isEmpty(defaultAttrPoJo.getDefaultType())) {
                    defaultAttrPoJo.setDefaultType(DefaultTypeEnum.DATE_BY_BACK_END.getAlias());
                }
                //付款日期字段：非自定义类型才设置默认值
                if (!Objects.equals(defaultAttrPoJo.getDefaultType(),DefaultTypeEnum.CUSTOM.getAlias())){
                    defaultAttrPoJo.setDefaultValue(DateTimeUtil.getInt());
                }
            }
        }
    }

    @Override
    public void formatLinkAddWriteOffPrepay(HandlerExplainInLinkItemDTO handlerExplainInLinkItemDTO) throws XbbException {
        JSONObject linkFormData = handlerExplainInLinkItemDTO.getLinkFormData();
        Long linkDataId = handlerExplainInLinkItemDTO.getLinkDataId();
        List<FieldAttrEntity> explainList = handlerExplainInLinkItemDTO.getExplainList();
        String corpid = handlerExplainInLinkItemDTO.getCorpid();
        FieldAttrEntity timeField = new FieldAttrEntity();
        FieldAttrEntity customerField = new FieldAttrEntity();
        FieldAttrEntity contractField = new FieldAttrEntity();
        FieldAttrEntity paymentField = new FieldAttrEntity();
        for(FieldAttrEntity fieldAttrEntity :explainList) {
            if (Objects.equals(fieldAttrEntity.getAttr(), PaySheetEnum.REAL_PAY_TIME.getAttr())) {
                timeField = fieldAttrEntity;
            } else if (Objects.equals(fieldAttrEntity.getAttr(), PaySheetEnum.LINK_SUPPLIER.getAttr())) {
                customerField = fieldAttrEntity;
            } else if (Objects.equals(fieldAttrEntity.getAttr(), PaySheetEnum.LINK_PURCHASE.getAttr())) {
                contractField = fieldAttrEntity;
            } else if (Objects.equals(fieldAttrEntity.getAttr(), PaySheetEnum.PAY_PLAN.getAttr())) {
                paymentField = fieldAttrEntity;
            }
        }
        RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(handlerExplainInLinkItemDTO.getLinkBusinessType());
        Long supplierId = 0L;
        //核销预付款需要根据返回当前客户下的预付款余额
        PayBalanceEntity payBalanceEntity;
        switch (redundantTemplateTypeEnum) {
            case PURCHASE:
                JSONArray purchaseSupplier = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, PurchaseEnum.SUPPLIER_ID.getAttr(), new JSONArray());
                supplierId = purchaseSupplier.getJSONObject(0).getLong(BasicConstant.ID);
                payBalanceEntity = payBalanceModel.getBySupplierId(supplierId, corpid);
                customerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojoByPayBalance(purchaseSupplier, payBalanceEntity));
                String contractNo = handlerExplainInLinkItemDTO.getPaasFormDataEntityExt().getSerialNo();
                contractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, contractNo));
                break;
            case PAY_PLAN:
                JSONArray payPlanSupplier = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, PayPlanEnum.LINK_SUPPLIER.getAttr(), new JSONArray());
                supplierId = payPlanSupplier.getJSONObject(0).getLong(BasicConstant.ID);
                payBalanceEntity = payBalanceModel.getBySupplierId(supplierId, corpid);
                customerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojoByPayBalance(payPlanSupplier, payBalanceEntity));
                JSONArray contractArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, PayPlanEnum.LINK_PURCHASE.getAttr(), new JSONArray());
                contractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(contractArray));
                paymentField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, handlerExplainInLinkItemDTO.getPaasFormDataEntityExt().getSerialNo()));
                break;
            case SUPPLIER:
                String supplierName = linkFormData.getString(SupplierEnum.SUPPLIER_NAME.getAttr());
                supplierId = linkDataId;
                payBalanceEntity = payBalanceModel.getBySupplierId(supplierId, corpid);
                customerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojoByPayBalance(linkDataId, supplierName, payBalanceEntity));
                break;
            default:
                throw new XbbException(TemplateErrorCodeEnum.API_ERROR_350006);
        }
        // 日期
        DefaultAttrPoJo timeDefaultAttrPoJo = timeField.getDefaultAttr();
        if (Objects.isNull(timeDefaultAttrPoJo)) {
            timeDefaultAttrPoJo = new DefaultAttrPoJo();
        }
        if (StringUtil.isEmpty(timeDefaultAttrPoJo.getDefaultType())) {
            timeDefaultAttrPoJo.setDefaultType(DefaultTypeEnum.DATE_BY_BACK_END.getAlias());
        }
        timeDefaultAttrPoJo.setDefaultValue(DateTimeUtil.getInt());
        timeField.setDefaultAttr(timeDefaultAttrPoJo);
        timeField.setAttrName("核销日期");
    }

    @Override
    public void formatLinkAddRedPrepayment(HandlerExplainInLinkItemDTO handlerExplainInLinkItemDTO) throws XbbException {
        JSONObject linkFormData = handlerExplainInLinkItemDTO.getLinkFormData();
        Long linkDataId = handlerExplainInLinkItemDTO.getLinkDataId();
        List<FieldAttrEntity> explainList = handlerExplainInLinkItemDTO.getExplainList();
        FieldAttrEntity customerField = new FieldAttrEntity();
        FieldAttrEntity timeField = new FieldAttrEntity();
        FieldAttrEntity fundAccountField = new FieldAttrEntity();
        for(FieldAttrEntity fieldAttrEntity : explainList) {
            if (Objects.equals(fieldAttrEntity.getAttr(), PaySheetEnum.LINK_SUPPLIER.getAttr())) {
                customerField = fieldAttrEntity;
            } else if (Objects.equals(fieldAttrEntity.getAttr(), PaySheetEnum.REAL_PAY_TIME.getAttr())) {
                timeField = fieldAttrEntity;
            } else if (Objects.equals(fieldAttrEntity.getAttr(), PaySheetEnum.FUND_ACCOUNT.getAttr())) {
                fundAccountField = fieldAttrEntity;
            }
        }
        PayBalanceEntity payBalanceEntity = payBalanceModel.getBySupplierId(linkDataId, handlerExplainInLinkItemDTO.getCorpid());
        // 关联供应商
        customerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojoByPayBalance(linkDataId, linkFormData.getString(SupplierEnum.SUPPLIER_NAME.getAttr()), payBalanceEntity));
        // 红冲日期
        DefaultAttrPoJo timeDefaultAttrPoJo = timeField.getDefaultAttr();
        if (StringUtil.isEmpty(timeDefaultAttrPoJo.getDefaultType())) {
            timeDefaultAttrPoJo.setDefaultType(DefaultTypeEnum.DATE_BY_BACK_END.getAlias());
        }
        timeDefaultAttrPoJo.setDefaultValue(DateTimeUtil.getInt());
        timeField.setDefaultAttr(timeDefaultAttrPoJo);
        //红冲资金账户
        String fundAccountValue = FastJsonHelper.getStringFromFormData(linkFormData, PaySheetEnum.FUND_ACCOUNT.getAttr());
        commonHelp.handleLinkAdd4Combo(fundAccountField, fundAccountValue);
    }



    @Override
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        payPlanSheetAnalyticalService.beforeSave(validateDataDTO);
    }

    @Override
    public PayPlanSheetDeleteBatchVO deleteBatch(PayPlanSheetDeleteBatchDTO payPlanSheetDeleteBatchDTO) throws XbbException{
        PayPlanSheetDeleteBatchVO payPlanSheetDeleteBatchVO = new PayPlanSheetDeleteBatchVO();
        List<Long> idIn = payPlanSheetDeleteBatchDTO.getIdIn();
        if (idIn.size() > BasicConstant.MAX_DEL_BATCH_COUNT) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100079, SystemErrorCodeEnum.API_ERROR_100079.getMsg(), BasicConstant.MAX_DEL_BATCH_COUNT);
        }
        String corpid = payPlanSheetDeleteBatchDTO.getCorpid();
        try {
            List<PaasFormDataEntityExt> sheetList = saasListHelp.getPaasFormDataList4Sheet(idIn, corpid, XbbRefTypeEnum.PAY_SHEET, IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET);
            deletePaySheet(payPlanSheetDeleteBatchDTO, payPlanSheetDeleteBatchVO, sheetList, corpid, payPlanSheetDeleteBatchDTO.getSingleFlag());
        } catch (XbbException e) {
            LOG.error("payPlanSheetServiceImpl.deleteBatch 批量删除付款单出错：", e);
            throw e;
        } catch (Exception e) {
            LOG.error("payPlanSheetServiceImpl.deleteBatch 批量删除付款单出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return payPlanSheetDeleteBatchVO;
    }

    @Override
    public Map<String, Double> handleRedSheetsBySheet(String corpid, Long sheetId, AmountDetailGetPojo amountDetailGetPojo) throws XbbException {
        // 查询该付款计划下面关联的所有付款单
        BoolQueryBuilder boolQueryBuilder = saasPaySheetHelper.getBoolQueryBuilder4LinkRed(corpid, Collections.singletonList(sheetId));
        List<String> fieldList = Arrays.asList(BasicConstant.ID, BasicConstant.DATAID, FieldTypeEnum.SHEET_ALONE.getAlias(), FieldTypeEnum.SHEET_UUID.getAlias(), PaySheetEnum.getAttrConnectData(PaySheetEnum.PAY_SHEET_TYPE), PaySheetEnum.getAttrConnectData(PaySheetEnum.AMOUNT), PaySheetEnum.getAttrConnectData(PaySheetEnum.WRITE_OFF_AMOUNT), PaySheetEnum.getAttrConnectData(PaySheetEnum.LINK_PURCHASE), PaySheetEnum.getAttrConnectData(PaySheetEnum.PAY_PLAN));
        //分页查询
        XbbAggregatedPage<PaasFormDataEntityExt> esEntities = esHelper.findByPage(IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, boolQueryBuilder, PaasFormDataEntityExt.class, fieldList, BasicConstant.ONE, EsNormalConstant.FIND_NUM, null);
        List<PaasFormDataEntityExt> sheetList = new ArrayList<>();
        if (esEntities != null) {
            sheetList = esEntities.getContent();
        }
        Set<String> uuidSet = new HashSet<>();
        /**
         key：红冲付款单的采购合同id_付款计划id
         value：红冲单据的金额
         */
        Map<String, Double> redCidPidAmountMap = new HashMap<>(sheetList.size());
        Double sumAmount = 0D;
        for (PaasFormDataEntityExt entityExt : sheetList) {
            JSONObject data = entityExt.getData();
            String paySheetType = FastJsonHelper.getStringFromFormData(data, PaySheetEnum.PAY_SHEET_TYPE.getAttr());
            double sheetAmount = FundHelp.getSheetAmount4PaySheet(data, paySheetType);
            sumAmount = Arith.add(sumAmount, sheetAmount);
            if (Objects.equals(entityExt.getAlone(), SheetAloneEnum.NORMAL.getCode())) {
                fundHelp.formatCidPidRedAmountMap(PaySheetEnum.LINK_PURCHASE.getAttr(), PaySheetEnum.PAY_PLAN.getAttr(), redCidPidAmountMap, entityExt, sheetAmount);
                continue;
            } else {
                //父单，则读取子单
                uuidSet.add(entityExt.getUuid());
            }
        }
        amountDetailGetPojo.setRedAmount(sumAmount);
        //如果有明细，则处理明细
        List<PaasFormDataEntityExt> childList = fundHelp.getChildEsDataListByParentUuids(XbbRefTypeEnum.PAY_SHEET, corpid, uuidSet, null, null);
        for (PaasFormDataEntityExt entityExt : childList) {
            JSONObject data = entityExt.getData();
            String paySheetType = FastJsonHelper.getStringFromFormData(data, PaySheetEnum.PAY_SHEET_TYPE.getAttr());
            double sheetAmount = FundHelp.getSheetAmount4PaySheet(data, paySheetType);
            fundHelp.formatCidPidRedAmountMap(PaySheetEnum.LINK_PURCHASE.getAttr(), PaySheetEnum.PAY_PLAN.getAttr(), redCidPidAmountMap, entityExt, sheetAmount);
        }
        amountDetailGetPojo.setRedCidPidAmountMap(redCidPidAmountMap);
        return redCidPidAmountMap;
    }

    /**
     * 只计算总的未付/已付金额即可，不用封装明细，但是要从每条付款计划内求和得到已付/未付总额（付款单保存验证金额时，需要获取总金额进行数值校验）
     * @param isRedFlag 是否红冲，如果红冲则读取关联原始付款单相关（红冲预付款不会关联采购合同和付款计划，不会调用该接口）
     * @param sheetAmountDetailGetDTO 获取付款单明细dto
     * @param dataIdList 采购合同id集合
     * @param payPlanEnum 未付/实付字段
     * @param purchaseEnum 未付/已付字段
     * @param corpid 公司id
     * @return SheetAmountDetailGetVO
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private SheetAmountDetailGetVO getResult4AmountDetailSum(boolean isRedFlag, SheetAmountDetailGetDTO sheetAmountDetailGetDTO, List<Long> dataIdList, PayPlanEnum payPlanEnum, PurchaseEnum purchaseEnum, String corpid) throws XbbException {
        SheetAmountDetailGetVO sheetAmountDetailGetVO = new SheetAmountDetailGetVO();
        //封装查询付款计划（未付或已付）的条件，如果是红冲的，还需要获得关联的原始付款单
        AmountDetailGetPojo amountDetailGetPojo = saasPayPlanHelper.getPaymentAmountDetailGetPojo(isRedFlag, sheetAmountDetailGetDTO);
        if (isRedFlag) {
            double redAmount = saasPaySheetHelper.sumRedAmountBySheet(corpid, sheetAmountDetailGetDTO.getLinkPreId());
            amountDetailGetPojo.setRedAmount(redAmount);
            fundHelp.subRedAmount(XbbRefTypeEnum.PAY_SHEET, sheetAmountDetailGetVO, amountDetailGetPojo);
        } else {
            // 得到付款计划（未付/已付）查询结果：只求总的未付/已付，则无需排序，因此explainMap、sortMap都传null
            List<PaasFormDataEntityExt> planList = getPlanList4AmountDetailGet(amountDetailGetPojo, sheetAmountDetailGetDTO, null, null);
            //拥有付款计划的采购合同id集合
            List<Long> hasPaymentCids = new ArrayList<>();
            Double sumAmount = 0D;
            for (PaasFormDataEntityExt entityExt : planList) {
                JSONObject data = entityExt.getData();
                Long purchaseId = data.getLongValue(PayPlanEnum.LINK_PURCHASE.getAttr());
                hasPaymentCids.add(purchaseId);
                //已付或未付金额
                Double amount = getDoubleOrDefaultFromFormData(data, payPlanEnum.getAttr(), 0D);
                sumAmount = Arith.add(sumAmount, amount);
            }
            //移除所有有付款计划的合同ids，剩余无付款计划的采购合同ids
            dataIdList.removeAll(hasPaymentCids);
            if (dataIdList.size() > 0) {
                List<String> fieldList = Arrays.asList(PurchaseEnum.getAttrConnectData(PurchaseEnum.TOTAL_MONEY), PurchaseEnum.getAttrConnectData(PurchaseEnum.FINISH_AMOUNT), PurchaseEnum.getAttrConnectData(PurchaseEnum.UN_FINISH_AMOUNT));
                List<PaasFormDataEntityExt> contracts = formHelp.getFormListByIds4All(corpid, IndexTypeEnum.IDX_SAAS_PURCHASE, dataIdList, fieldList);
                for (PaasFormDataEntityExt entityExt : contracts) {
                    //已付或未付金额
                    Double amount = getDoubleOrDefaultFromFormData(entityExt.getData(), purchaseEnum.getAttr(), 0D);
                    sumAmount = Arith.add(sumAmount, amount);
                }
            }
            sheetAmountDetailGetVO.setSumAmount(sumAmount);
        }
        return sheetAmountDetailGetVO;
    }

    /**
     * 除了计算总的未付/已付金额，还要处理封装明细-按顺序封装明细内所有东西：签订人、金额、采购合同编号、付款计划编号等
     * 注：最后封装的明细排序规则为：（1）第一层按照前端传入的采购合同id顺序（dataIdList的顺序）；（2）第二层内层按照付款计划预计付款时间升序-红冲则直接按照原单的明细进行渲染
     * @param isRedFlag 是否红冲，如果红冲则读取关联原始付款单相关及其子单（红冲预付款不会关联采购合同和付款计划，不会调用该接口）；否则读取付款计划的未付款
     * @param sheetAmountDetailGetDTO 获取付款单明细dto
     * @param dataIdList 采购合同id集合
     * @param payPlanEnum 未付/实付字段
     * @param purchaseEnum 未付/已付字段
     * @param corpid 公司id
     * @return SheetAmountDetailGetVO
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private SheetAmountDetailGetVO getResult4AmountDetail(String corpid, boolean isRedFlag, SheetAmountDetailGetDTO sheetAmountDetailGetDTO, List<Long> dataIdList, PayPlanEnum payPlanEnum, PurchaseEnum purchaseEnum) throws XbbException {
        //封装查询付款计划（未付或已付）的条件，如果是红冲的，只需要获得关联的原始付款单
        AmountDetailGetPojo amountDetailGetPojo = saasPayPlanHelper.getPaymentAmountDetailGetPojo(isRedFlag, sheetAmountDetailGetDTO);
        SheetAmountDetailGetVO sheetAmountDetailGetVO = new SheetAmountDetailGetVO();
        //采购合同id-该合同的付款计划/付款单list（把同一个采购合同的付款计划/付款单放到一起）
        Map<Long, List<JSONObject>> resultMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (isRedFlag) {
            //创建红冲付款单，则只需读取到关联原始付款单，及其子单，然后明细通过其本身或子单进行渲染（只能红冲原单的已付）
            PaasFormDataEntityExt linkSheetEntity = amountDetailGetPojo.getLinkSheetEntity();
            //确保每个数据关联的采购合同、付款计划都是一条（因为sheetList内只塞入子、及无子的付款单，而这类付款单都是只关联一个）
            List<PaasFormDataEntityExt> sheetList = new ArrayList<>();
            if (Objects.equals(linkSheetEntity.getAlone(), SheetAloneEnum.PARENT.getCode())) {
                //查询出所有子付款单
                sheetList.addAll(fundHelp.getChildEsDataListByParentUuid(IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, corpid, linkSheetEntity.getUuid(), null));
            } else {
                //无父子回款单则塞入本身
                sheetList.add(linkSheetEntity);
            }
            /**
             key：红冲付款单的采购合同id_付款计划id
             value：红冲单据的金额
             */
            Map<String, Double> redCidPidAmountMap = handleRedSheetsBySheet(corpid, sheetAmountDetailGetDTO.getLinkPreId(), amountDetailGetPojo);
            Set<String> belongUserSet = new HashSet<>();
            for (PaasFormDataEntityExt entityExt : sheetList) {
                JSONArray belongArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(entityExt.getData(), PaySheetEnum.BELONG_ID.getAttr(), new JSONArray());
                if (belongArr.size() > 0) {
                    List<String> belongList = belongArr.toJavaList(String.class);
                    belongUserSet.addAll(belongList);
                }
            }
            //归属人userId-归属人姓名
            Map<String, String> belongNameMap = commonHelp.getUserNameMapByIds(corpid, belongUserSet);
            for (PaasFormDataEntityExt entityExt : sheetList) {
                JSONObject data = entityExt.getData();
                String paySheetType = FastJsonHelper.getStringFromFormData(data, PaySheetEnum.PAY_SHEET_TYPE.getAttr());
                JSONArray idArr = FastJsonHelper.getJsonArrFromFormData(data, PaySheetEnum.LINK_PURCHASE.getAttr());
                if (idArr == null || idArr.isEmpty()) {
                    continue;
                }
                JSONArray contractNoArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaySheetEnum.PURCHASE_LINK_TEXT.getAttr(), new JSONArray());
                //都是一条（因为sheetList内只塞入子、及无子的付款单，而这类付款单都是只关联一个）
                Long contractId = idArr.getLong(0);
                String contractSerialNo = (contractNoArr.size() <= 0) ? "" : contractNoArr.getString(0);
                JSONArray belongArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaySheetEnum.BELONG_ID.getAttr(), new JSONArray());
                //红冲付款单直接用原单的归属人
                String belongUserId = (belongArr.size() <= 0)? "": belongArr.getString(0);
                String belongName = belongNameMap.getOrDefault(belongUserId, "");
                //付款计划信息
                List<Long> pidList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaySheetEnum.PAY_PLAN.getAttr(), new JSONArray()).toJavaList(Long.class);
                List<IdNamePojo> paymentInfo = null;
                String key = contractId + "";
                if (pidList.size() > 0) {
                    Long paymentId = pidList.get(0);
                    key += "_" + paymentId;
                    JSONArray nameArr = FastJsonHelper.getJsonArrFromFormData(data, PaySheetEnum.PAY_PLAN_LINK_TEXT.getAttr());
                    String paymentSerialNo = nameArr.getString(0);
                    paymentInfo = Collections.singletonList(new IdNamePojo(paymentId, paymentSerialNo));
                }
                double sheetAmount = FundHelp.getSheetAmount4PaySheet(data, paySheetType);
                //关联了采购合同、付款计划的明细红冲金额，此时为负值
                Double sheetRedAmount = redCidPidAmountMap.getOrDefault(key, 0D);
                Double left = Arith.add(sheetAmount, sheetRedAmount);
                if (left == 0) {
                    continue;
                }
                JSONObject jsonObject = sheetAmountDetailGetVO.formatInfo4Pay(contractId, contractSerialNo, belongUserId, belongName, paymentInfo, left, left);
                List<JSONObject> list = resultMap.getOrDefault(contractId, new ArrayList<>());
                list.add(jsonObject);
                resultMap.put(contractId, list);
            }
            //最后封装的明细排序规则为：按照前端传入的采购合同id顺序（dataIdList的顺序）
            List<JSONObject> list = new ArrayList<>();
            for (Long contractId : dataIdList) {
                if (resultMap.get(contractId) != null) {
                    list.addAll(resultMap.get(contractId));
                }
            }
            fundHelp.subRedAmount(XbbRefTypeEnum.PAY_SHEET, sheetAmountDetailGetVO, amountDetailGetPojo);
            sheetAmountDetailGetVO.setList(list);
        } else {
            //非红冲，则读取付款计划的未付
            //付款计划排序，内部排序方法需要用到explainMap
            PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByBusinessType(RedundantTemplateTypeEnum.PAY_PLAN.getCode(), corpid);
            if (Objects.isNull(paasFormExplainEntity)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
            }
            //排序字段：预计付款时间升序
            Map<String, String> sortMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            sortMap.put("field", PayPlanEnum.ESTIMATE_TIME.getAttr());
            sortMap.put("sort", SortOrder.ASC.toString());
            Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);
            //得到付款计划（未付/已付）查询结果：需对计划排序，因此需要explainMap、sortMap
            List<PaasFormDataEntityExt> planList = getPlanList4AmountDetailGet(amountDetailGetPojo, sheetAmountDetailGetDTO, explainMap, sortMap);
            //合同id-签订人userId
            Map<Long, String> cidSignPersonMap = new HashMap<>(dataIdList.size());
            //合同id-合同信息
            Map<Long, PaasFormDataEntityExt> cidMap = new HashMap<>(dataIdList.size());
            //签订人userId-签订人姓名
            Map<String, String> signNameMap = handleContractInfo(corpid, dataIdList, cidSignPersonMap, cidMap);
            String attrPlan = payPlanEnum.getAttr();
            String attrContract = purchaseEnum.getAttr();
            String attrContract4Plan = PayPlanEnum.LINK_PURCHASE.getAttr();
            //封装最终结果：（1）第一层按照前端传入的采购合同id顺序（dataIdList的顺序）；（2）第二层内层按照付款计划预计付款时间升序-红冲则直接按照原单的明细进行渲染
            fundHelp.formatDetailResult(false, sheetAmountDetailGetVO, dataIdList, resultMap, planList, cidMap, cidSignPersonMap, signNameMap, attrPlan, attrContract, attrContract4Plan);
        }
        return sheetAmountDetailGetVO;
    }

    /**
     * 根据关联id和条件获取数据
     * @param amountDetailGetPojo 获取金额明细时需要用到的条件、原单信息pojo
     * @param sheetAmountDetailGetDTO dto
     * @param explainMap 解释map（排序时用到）
     * @param sortMap 排序map
     * @return AmountDetailGetPojo
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private List<PaasFormDataEntityExt> getPlanList4AmountDetailGet(AmountDetailGetPojo amountDetailGetPojo, SheetAmountDetailGetDTO sheetAmountDetailGetDTO, Map<String, FieldAttrEntity> explainMap, Map<String, String> sortMap) throws XbbException {
        //查询出部分字段（其他id、dataId等字段内部会强制加上去，无需重复置入）
        List<String> fieldList = Arrays.asList(PayPlanEnum.LINK_PURCHASE.getAttr(), PayPlanEnum.UN_AMOUNT.getAttr(), PayPlanEnum.REAL_AMOUNT.getAttr());
        FormDataListDTO formDataListDTO = new FormDataListDTO();
        BeanUtil.copyProperties(sheetAmountDetailGetDTO, formDataListDTO);
        formDataListDTO.setAppId(null);
        formDataListDTO.setFormId(null);
        formDataListDTO.setDel(DelEnum.NORMAL.getDel());
        formDataListDTO.setConditions(amountDetailGetPojo.getConditionList());
        formDataListDTO.setBusinessType(XbbRefTypeEnum.PAY_PLAN.getCode());
        formDataListDTO.setSortMap(sortMap);
        formDataListDTO.setExplainMap(explainMap);
        formDataListDTO.setFieldList(fieldList);
        formDataListDTO.setSearchSubForm(false);
        PaasFormDataEsListVO paasFormDataEsListVO = paasFormDataEsModel.list(formDataListDTO, IndexTypeEnum.IDX_SAAS_PAY_PLAN);
        PageHelper pageHelper = paasFormDataEsListVO.getPageHelper();
        if (pageHelper.getRowsCount() > SizeConstant.PAGE_SIZE) {
            //查询采购合同下的付款计划时，限制只能查询1w条
            throw new XbbException(PayErrorCodeEnum.API_ERROR_226017, PayErrorCodeEnum.API_ERROR_226017.getMsg(), SizeConstant.PAGE_SIZE);
        }
        return paasFormDataEsListVO.getPaasFormDataESList();
    }

    /**
     * 查询采购合同信息，并处理构建采购合同id和采购合同一些信息的对应关系map，以及签订人userId和签订人名称对应关系map
     * @param corpid 公司id
     * @param dataIdList 采购合同id集合
     * @param cidSignPersonMap 采购合同id-签订人userId
     * @param cidMap 采购合同id-合同信息
     * @return java.util.Map<java.lang.String,java.lang.String>
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private Map<String, String> handleContractInfo(String corpid, List<Long> dataIdList, Map<Long, String> cidSignPersonMap, Map<Long, PaasFormDataEntityExt> cidMap) throws XbbException {
        List<String> fieldList = Arrays.asList("id", PurchaseEnum.SHEET_NO.getAttr(), PurchaseEnum.getAttrConnectData(PurchaseEnum.TOTAL_MONEY), PurchaseEnum.getAttrConnectData(PurchaseEnum.FINISH_AMOUNT), PurchaseEnum.getAttrConnectData(PurchaseEnum.UN_FINISH_AMOUNT), PurchaseEnum.getAttrConnectData(PurchaseEnum.SIGNER_ID));
        List<PaasFormDataEntityExt> contracts = formHelp.getFormListByIds4All(corpid, IndexTypeEnum.IDX_SAAS_PURCHASE, dataIdList, fieldList);
        Set<String> signUserIds = new HashSet<>();
        for (PaasFormDataEntityExt entityExt : contracts) {
            String signUserId = FastJsonHelper.getStringOrDefaultFromFormData(entityExt.getData(), PurchaseEnum.SIGNER_ID.getAttr(), "-1");
            signUserIds.add(signUserId);
            cidSignPersonMap.put(entityExt.getId(), signUserId);
            cidMap.put(entityExt.getId(), entityExt);
        }
        //签订人userId-签订人姓名
        return commonHelp.getUserNameMapByIds(corpid, signUserIds);
    }

    /**
     * 批量保存前置
     *
     * @param formDataSaveDTO
     * @param paySheetTypeEnum 付款单类型
     * @param supplierId
     * @return
     * @throws XbbException
     * @author chenshan
     * @date 2020-02-27 15:30:11
     */
    @Override
    public AddBatchDTO beforeSaveBatch(FormDataAddDTO formDataSaveDTO, PaySheetTypeEnum paySheetTypeEnum, Long supplierId) throws XbbException {
        Map<String, Object> params = BeanUtil.convertBean2Map(formDataSaveDTO, true);
        List<PaasFormExplainEntity> explainList = paasFormExplainModel.list(params);
        if (Objects.isNull(explainList) || explainList.isEmpty()) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explainList.get(0).getExplains(), null);
        JSONObject data = formDataSaveDTO.getDataList();
        saasSaveHelp.formatLinkBusiness4Save(data, PaySheetEnum.LINK_SUPPLIER.getAttr(), PaySheetEnum.SUPPLIER_LINK_TEXT.getAttr(), PaySheetEnum.LINK_SUPPLIER.getFieldType());
        saasSaveHelp.formatLinkBusiness4Save(data, PaySheetEnum.LINK_PURCHASE.getAttr(), PaySheetEnum.PURCHASE_LINK_TEXT.getAttr(), PaySheetEnum.LINK_PURCHASE.getFieldType());
        Double purchaseAmount;
        // 来自于合同新建编辑
        SaasNeedRedundantAttrPojo saasNeedRedundantAttrPoJo = formDataSaveDTO.getSaasNeedRedundantAttrPoJo();
        if (Objects.nonNull(saasNeedRedundantAttrPoJo) && Objects.equals(saasNeedRedundantAttrPoJo.getParentBusinessType(), XbbRefTypeEnum.PURCHASE.getCode())) {
            purchaseAmount = formDataSaveDTO.getSaasNeedRedundantAttrPoJo().getParentAmount();
        } else {
            JSONArray idArray = data.getJSONArray(PaySheetEnum.LINK_PURCHASE.getAttr());
            Long dataId = 0L;
            if ( CollectionsUtil.isNotEmpty(idArray) ) {
                dataId = idArray.getLong(0);
            }
            PaasFormDataEntityExt purchaseEntityExt = purchaseModel.getByKey(dataId,formDataSaveDTO.getCorpid());
            if (Objects.isNull(purchaseEntityExt)) {
                throw new XbbException(ContractErrorCodeEnum.API_ERROR_203001);
            }
            purchaseAmount = purchaseEntityExt.getData().getDouble(PurchaseEnum.TOTAL_MONEY.getAttr());
        }
        Double paySheetAmount = 0D;
        Double advancePayBalance = 0D;
        JSONArray paySheetArray = data.getJSONArray(PurchaseEnum.ADD_PAY_SHEET.getAttr());
        String xbbRefTypeName = XbbRefTypeEnum.PAY_SHEET.getName();
        if ( Objects.equals(PaySheetTypeEnum.WRITE_OFF_PREPAY.getCode(), paySheetTypeEnum.getCode()) ){
            paySheetArray = data.getJSONArray(PurchaseEnum.ADD_WRITE_OFF_PREPAY.getAttr());
            xbbRefTypeName = XbbRefTypeEnum.WRITE_OFF_PREPAY.getName();
        }

        List<AddMuchFieldPojo> addBatchList = new ArrayList<>();
        List<AddMuchFieldPojo> delBatchList = new ArrayList<>();
        List<AddMuchFieldPojo> updateBatchList = new ArrayList<>();
        List<ValidateDataDTO> validateDataDTOList = new ArrayList<>();
        FieldAttrEntity serialNoEntity = explainMap.get(PurchaseEnum.SHEET_NO.getAttr());
        //下面是移除审批中已经删除的付款单
        paasFormExplainService.handProcessShouldRemoveValue(formDataSaveDTO.getCorpid(), XbbRefTypeEnum.PURCHASE, XbbRefTypeEnum.PAY_SHEET, paySheetArray);
        for (Object obj : paySheetArray){
            AddMuchFieldPojo addMuchFieldPojo = new AddMuchFieldPojo();
            ValidateDataDTO validateDataDTO = new ValidateDataDTO();
            JSONObject json = (JSONObject) obj;
            Long dataId = json.getLong(StringConstant.DATA_ID);
            addMuchFieldPojo.setId(dataId);
            String serialNo = json.getString(FieldTypeEnum.SERIALNO.getAlias());
            // 开启严控模式
            if (Objects.nonNull(serialNoEntity) && Objects.equals(serialNoEntity.getStrictController(), BasicConstant.ONE) && StringUtil.isEmpty(serialNo)) {
                serialNo = saasSaveHelp.getSerialNo(serialNo, formDataSaveDTO, formDataSaveDTO.getCorpid(), serialNoEntity);
                addMuchFieldPojo.setSerialNo(serialNo);
                formDataSaveDTO.setSerialNo(serialNo);
                json.getJSONObject("data").put(FieldTypeEnum.SERIALNO.getAlias(), serialNo);
            }
            if ( StringUtil.isNotEmpty(serialNo) && serialNo.length()>BasicConstant.SERIAL_LENGTH_NUMBER) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208059,String.format(PaymentErrorCodeEnum.API_ERROR_208059.getMsg(),xbbRefTypeName,BasicConstant.SERIAL_LENGTH_NUMBER));
            }
            addMuchFieldPojo.setSerialNo(serialNo);
            JSONObject paySheetData = json.getJSONObject("data");
            Integer alone = json.getInteger(BasicConstant.ALONE);
            boolean flag = Objects.isNull(dataId) && (Objects.isNull(alone) || Objects.equals(alone, SheetAloneEnum.NORMAL.getCode()));
            if (flag) {
                JSONArray belongIdArray = paySheetData.getJSONArray(PaySheetEnum.BELONG_ID.getAttr());
                if ( belongIdArray.size() > 1 ){
                    throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208047, PaymentErrorCodeEnum.API_ERROR_208047.getMsg(), paySheetTypeEnum.getName());
                }
            }
            for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPayPlanSheet().entrySet()){
                SaasDataInitHelp.antDataSet(paySheetData,entry.getKey(),entry.getValue());
            }
            if ( Objects.equals(PaySheetTypeEnum.WRITE_OFF_PAY.getCode(), paySheetTypeEnum.getCode()) ){
                paySheetData.put(PaySheetEnum.WRITE_OFF_AMOUNT.getAttr(), getDoubleOrDefaultFromFormData(paySheetData, PaySheetEnum.AMOUNT.getAttr(), 0D));
            }
            if ( Objects.isNull(dataId)) {
                paySheetData.put(PaySheetEnum.PAY_SHEET_TYPE.getAttr(), paySheetTypeEnum.getCode());
            }
            paySheetData.put(PaySheetEnum.LINK_SUPPLIER.getAttr(),data.get(PaySheetEnum.LINK_SUPPLIER.getAttr()));
            paySheetData.put(PaySheetEnum.SUPPLIER_LINK_TEXT.getAttr(),data.get(PaySheetEnum.SUPPLIER_LINK_TEXT.getAttr()));
            paySheetData.put(PaySheetEnum.LINK_PURCHASE.getAttr(),data.get(PaySheetEnum.LINK_PURCHASE.getAttr()));
            paySheetData.put(PaySheetEnum.PURCHASE_LINK_TEXT.getAttr(),data.get(PaySheetEnum.PURCHASE_LINK_TEXT.getAttr()));
            Integer operationFlag = json.getInteger(StringConstant.OPERATION_FLAG);
            addMuchFieldPojo.setData(paySheetData);
            if ( Objects.isNull(dataId) ) {
                operationFlag = null;
            }
            BeanUtil.copyProperties(formDataSaveDTO,validateDataDTO);
            validateDataDTO.setSerialNo(serialNo);
            validateDataDTO.setBusinessType(XbbRefTypeEnum.PAY_SHEET.getCode());
            validateDataDTO.setData(addMuchFieldPojo.getData());
            validateDataDTO.setDataId(dataId);
            if (Objects.equals(operationFlag, LinkAddOperationFlagEnum.DEL.getCode())){
                delBatchList.add(addMuchFieldPojo);
            }else {
                if (Objects.equals(operationFlag,LinkAddOperationFlagEnum.EDIT.getCode())){
                    updateBatchList.add(addMuchFieldPojo);
                    validateDataDTOList.add(validateDataDTO);
                    validateTeam(paySheetData, validateDataDTO, addMuchFieldPojo);
                }else if (Objects.isNull(dataId)){
                    //为了防止进入审批，前置传入
                    addMuchFieldPojo.setAlone(SheetAloneEnum.NORMAL.getCode());
                    addMuchFieldPojo.setUuid(UUID.randomUUID().toString());
                    addBatchList.add(addMuchFieldPojo);
                    validateDataDTOList.add(validateDataDTO);
                    if ( Objects.equals(PaySheetTypeEnum.WRITE_OFF_PREPAY.getCode(), paySheetTypeEnum.getCode()) ) {
                        advancePayBalance = Arith.add(advancePayBalance, getDoubleOrDefaultFromFormData(paySheetData, PaySheetEnum.WRITE_OFF_AMOUNT.getAttr(), 0D));
                    }
                    validateTeam(paySheetData, validateDataDTO, addMuchFieldPojo);
                }
                if ( Objects.equals(PaySheetTypeEnum.WRITE_OFF_PREPAY.getCode(), paySheetTypeEnum.getCode())  ){
                    paySheetAmount = Arith.add(paySheetAmount, getDoubleOrDefaultFromFormData(paySheetData, PaySheetEnum.WRITE_OFF_AMOUNT.getAttr(), 0D));
                } else {
                    paySheetAmount = Arith.add(paySheetAmount, getDoubleOrDefaultFromFormData(paySheetData, PaySheetEnum.AMOUNT.getAttr(), 0D));
                }
            }
            validateDataDTO.setExplainMap(explainMap);
            // 标签设置
            saasSaveHelp.dealLabelData(validateDataDTO.getData(), validateDataDTO.getExplainMap());
            formDataValidateDataHelp.validateData(validateDataDTO);
            ProSaveHelp.analyticalData(validateDataDTO);
            addMuchFieldPojo.setDepartmentId(validateDataDTO.getDepartmentId());
            paySheetData.put(FieldTypeEnum.DEPARTMENTID.getAlias(), validateDataDTO.getDepartmentId());
        }
        if ( Objects.equals(PaySheetTypeEnum.WRITE_OFF_PREPAY.getCode(), paySheetTypeEnum.getCode()) && advancePayBalance > 0 ) {
            PayBalanceEntity payBalanceEntity = payBalanceModel.getBySupplierId(supplierId, formDataSaveDTO.getCorpid());
            if ( payBalanceEntity == null || payBalanceEntity.getAdvancePayBalance() < advancePayBalance ) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208057, PaymentErrorCodeEnum.API_ERROR_208057.getMsg());
            }
        }
        //允许误差小于等于ConfigConstant.amountAccuracy
        if (Arith.sub(paySheetAmount, purchaseAmount) > ConfigConstant.amountAccuracy) {
            throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208046, PaymentErrorCodeEnum.API_ERROR_208046.getMsg(), paySheetTypeEnum.getName());
        }
        AddBatchDTO addBatchDTO = new AddBatchDTO();
        BeanUtil.copyProperties(formDataSaveDTO,addBatchDTO);
        addBatchDTO.setAddBatchList(addBatchList);
        FieldAttrEntity serialField = explainMap.getOrDefault(PaySheetEnum.PAY_PLAN_NO.getAttr(), new FieldAttrEntity());
        if (Objects.equals(serialField.getNoRepeat(), 1)) {
            Set<String> addSerialNoSet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            addBatchList.forEach(addBatch-> addSerialNoSet.add(addBatch.getSerialNo()));
            if (!Objects.equals(addSerialNoSet.size(), addBatchList.size())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.NO_REPEAT, serialField.getAttrName());
            }
        }
        Integer total = addBatchList.size() + updateBatchList.size() - delBatchList.size();
        if ( Objects.equals(paySheetTypeEnum.getCode(), PaySheetTypeEnum.WRITE_OFF_PREPAY.getCode()) ){
            if ( total > StringConstant.MAX_WRITE_OFF_PREPAY_COUNT ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.OVER_STEP_MAX_WRITE_OFF_PREPAY_COUNT, StringConstant.MAX_WRITE_OFF_PREPAY_COUNT);
            }
        } else if (Objects.equals(paySheetTypeEnum.getCode(), PaySheetTypeEnum.WRITE_OFF_PAY.getCode())){
            if ( total > StringConstant.MAX_PAY_SHEET_COUNT ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.OVER_STEP_MAX_PAY_SHEET_COUNT, StringConstant.MAX_PAY_SHEET_COUNT);
            }
        }
        addBatchDTO.setAmount(paySheetAmount);
        addBatchDTO.setUpdateBatchList(updateBatchList);
        addBatchDTO.setDelBatchList(delBatchList);
        addBatchDTO.setValidateDataDTOList(validateDataDTOList);
        return addBatchDTO;
    }

    /**
     * 校验团队并且往参数中封装团队信息
     *
     * @param json
     * @param validateDataDTO
     * @param addMuchFieldPojo
     * @param
     */
    private void validateTeam(JSONObject json, ValidateDataDTO validateDataDTO, AddMuchFieldPojo addMuchFieldPojo) throws XbbException {
        JSONArray teamMainPojoArray = json.getJSONArray(FieldTypeEnum.OWNERID.getAlias());
        JSONArray teamCoPojoArray = json.getJSONArray(FieldTypeEnum.COUSERID.getAlias());
        //因为采购合同批量新建付款计划的时候，validateDataDTO最外层也有采购合同的负责任人、协同人，所以需要把最外层的先移除掉
        validateDataDTO.setOwnerIds(null);
        validateDataDTO.setCoUserId(null);
        if (Objects.nonNull(teamMainPojoArray) && teamMainPojoArray.size() > BasicConstant.ZERO) {
            List<ReturnUserAndDepartmentPojo> ownerIds = teamMainPojoArray.toJavaList(ReturnUserAndDepartmentPojo.class);
            validateDataDTO.setOwnerIds(ownerIds);
        }
        if (Objects.nonNull(teamCoPojoArray) && teamCoPojoArray.size() > BasicConstant.ZERO) {
            List<ReturnUserAndDepartmentPojo> coUserIds = teamCoPojoArray.toJavaList(ReturnUserAndDepartmentPojo.class);
            validateDataDTO.setCoUserId(coUserIds);
        }
        teamUserHelp.beforeVerifyUserTeam(validateDataDTO);
        TeamAfterVerifyDTO teamAfterVerifyDTO = validateDataDTO.getSaasNeedRedundantAttrPoJo().getTeamAfterVerifyDTO();
        addMuchFieldPojo.setTeamAfterVerifyDTO(teamAfterVerifyDTO);
    }

    @Override
    public void updateRollback(Collection<Long> idIn, String corpid) throws XbbException {
        if (Objects.isNull(idIn) || idIn.isEmpty()) {
            return;
        }
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(StringConstant.CORPID, corpid);
        param.put("idIn", idIn);
        List<PayPlanSheetEntityExt> sheetList = payPlanSheetModel.findEntitysWithoutSub(param);
        if (sheetList == null || sheetList.size() == 0) {
            return;
        }
        for (PayPlanSheetEntityExt item : sheetList) {
            PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
            BeanUtil.copyProperties(item, paasFormDataEntity);
            proEsHelper.reductionEsInUpdate(paasFormDataEntity, item.getId(), corpid, IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET);
        }
    }

    /**
     * 新增失败的回滚-直接删除es
     * @param list
     * @param corpid
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void addRollbackList(List<PayPlanSheetEntityExt> list, String corpid) throws XbbException {
        if (list == null || list.size() == 0) {
            return;
        }
        IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET;
        for (PayPlanSheetEntityExt item : list) {
            if (Objects.isNull(item.getId())) {
                continue;
            }
            //新增的数据，物理删除
            proEsHelper.physicalDeleteAllInAdd(item.getId(), corpid, indexTypeEnum);
        }
    }

    /**
     * 已核销、预付款核销保存
     * 预付款核销需要处理预付款的余额，且预付款核销的【付款金额】需置为空
     * @param sheetTypeEnum 回/付款类型
     * @param payPlanSheetInsertDTO 保存dto
     * @param paasFormDataEntity 数据实体
     * @param paasFormEntityExt 表单form
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void writeOffSave(SheetTypeEnum sheetTypeEnum, PayPlanSheetInsertDTO payPlanSheetInsertDTO, PaasFormDataEntity paasFormDataEntity, PaasFormEntityExt paasFormEntityExt) throws XbbException{
        /*
         已核销付款：付款金额、核销金额同时置值
         */
        JSONObject dataList = payPlanSheetInsertDTO.getDataList();
        String corpid = payPlanSheetInsertDTO.getCorpid();
        String userId = payPlanSheetInsertDTO.getUserId();
        if (Objects.nonNull(payPlanSheetInsertDTO.getProcessCreatorId())) {
            userId = payPlanSheetInsertDTO.getProcessCreatorId();
        }
        JSONArray amountDetails = payPlanSheetInsertDTO.getAmountDetail();
        double allAmount = 0D;
        //付款计划和采购合同对应的付款金额
        Map<Long, Double> contractIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> paymentIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> contractIds = new HashSet<>();
        Set<Long> paymentIds = new HashSet<>();
        //回/付款单的实付回/付款金额
        Double sheetAmount;
        boolean writeOffPrepaymentFlag = SheetTypeEnum.isWriteOffPre(sheetTypeEnum);
        SheetAttrPojo sheetAttrPojo = new SheetAttrPojo(sheetTypeEnum.getXbbRefTypeEnum());
        if (writeOffPrepaymentFlag) {
            //预付/付款核销，是用的核销金额
            sheetAmount = getDoubleOrDefaultFromFormData(dataList, sheetAttrPojo.getAttrWriteOffAmount(), 0D);
            //检查预付/付款核销金额是否小于客户/供应商余额
            checkBalance(dataList, corpid, sheetAmount);
        } else {
            sheetAmount = getDoubleOrDefaultFromFormData(dataList, sheetAttrPojo.getAttrAmount(), 0D);
        }
        //处理金额明细
        List<JSONObject> sonSheetDataList = saasSaveHelp.handleAmountDetail(payPlanSheetInsertDTO, sheetAmount, sheetTypeEnum, sheetAttrPojo, dataList, amountDetails, allAmount, contractIdToAmount, paymentIdToAmount, contractIds, paymentIds);
        Double sumAmount = getSumAmount(payPlanSheetInsertDTO, contractIds, paymentIds, null);
        if (Arith.sub(sheetAmount , sumAmount) > ConfigConstant.amountAccuracy) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.BEYOND_AMOUNT_PAY);
        }
        //处理付款计划并封装要更新的结果：判断已付金额是否已经超过付款计划内的未付金额，并把付款计划的已付金额增加及更改其付款状态等
        List<UpdateDataEntity> updatePayList = payPlanService.handlePlan(sheetTypeEnum, dataList, corpid, paymentIdToAmount, paymentIds);
        //处理采购合同并封装要更新的结果：判断已付金额是否已经超过采购合同内的未付金额，并把采购合同的已付金额增加等
        List<UpdateDataEntity> updateConList = purchaseService.handleContract(sheetTypeEnum, corpid, contractIdToAmount, contractIds);
        PayPlanSheetEntityExt payPlanSheetEntityExt = new PayPlanSheetEntityExt();
        BeanUtil.copyProperties(paasFormDataEntity, payPlanSheetEntityExt);
        fundHelp.initSheetEntity4Save(userId, payPlanSheetEntityExt);
        for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPayPlanSheet().entrySet()){
            SaasDataInitHelp.antDataSet(dataList,entry.getKey(),entry.getValue());
        }
        long now = DateUtil.getNow();
        payPlanSheetEntityExt.setData(dataList);
        String uuid = UUID.randomUUID().toString();
        payPlanSheetEntityExt.setUuid(uuid);
        payPlanSheetEntityExt.setAddTime(now);
        payPlanSheetEntityExt.setUpdateTime(now);
        //插入父付款、子付款
        if (sonSheetDataList.size() > BasicConstant.ONE) {
            payPlanSheetEntityExt.setAlone(SheetAloneEnum.PARENT.getCode());
        } else {
            //没有明细，父子合并
            payPlanSheetEntityExt.setAlone(SheetAloneEnum.NORMAL.getCode());
        }
        List<PayPlanSheetEntityExt> sonSheetList = null;
        Long sheetId = null;
        //预付款核销不入流水，但普通核销入流水
        boolean flowFlag = !writeOffPrepaymentFlag;
        try {
            payPlanSheetModel.save(payPlanSheetEntityExt);
            sheetId = payPlanSheetEntityExt.getId();
            //回滚ES 需要dataID
            paasFormDataEntity.setId(sheetId);
            sonSheetList = saasPaySheetHelper.saveSheetSon(corpid, sonSheetDataList, payPlanSheetEntityExt, uuid);
            //更新付款计划/合同
            saasPayPlanHelper.savePayPlan(corpid, updatePayList, "PayPlanSheetServiceImpl.writeOffSave：新建已核销付款单更新付款计划时失败");
            purchaseHelp.savePurchase(corpid, updateConList, "PayPlanSheetServiceImpl.writeOffSave：新建已核销付款单更新采购合同时失败");
            if (writeOffPrepaymentFlag) {
                //核销预付款付款单新建时，减少预付款余额
                saasPaySheetHelper.saveBySheet(payPlanSheetEntityExt);
            } else {
                Long addTime = payPlanSheetEntityExt.getAddTime();
                Long accountId = FastJsonHelper.getLongOrDefaultFromFormData(dataList, PaySheetEnum.FUND_ACCOUNT.getAttr(), 0L);
                Long sheetTime = fundHelp.getSheetTime4FundFlow(dataList, PaySheetEnum.REAL_PAY_TIME.getAttr(), payPlanSheetInsertDTO.getExplainMap(), addTime);
                //账户余额变动 付款取反
                sheetAmount = Arith.mul(sheetAmount, -1);
                payAndPaymentSheetHelp.saveByPaymentSheetOrPaySheet(accountId, sheetAmount, corpid);
                //流水表日志记录
                FundAccountFlowEntity fundAccountFlowEntity = new FundAccountFlowEntity(corpid, addTime, payPlanSheetEntityExt.getCreatorId(), FundAccountFlowTypeEnum.PAY_SHEET.getCode(), payPlanSheetEntityExt.getId(), accountId, sheetTime, sheetAmount);
                fundAccountFlowModel.insert(fundAccountFlowEntity);

            }
            //处理付款单团队-必须在团队保存后执行，需要用到付款单的id
            handleSheetTeam(dataList, corpid, sheetTypeEnum, payPlanSheetEntityExt, sonSheetList);
            saasSaveHelp.sheetAddLog(payPlanSheetInsertDTO, corpid, userId, payPlanSheetEntityExt, XbbRefTypeEnum.PAY_SHEET.getName(), OperateModuleTypeEnum.PayManage);
            // 添加推送消息
            sheetAddMessage(payPlanSheetInsertDTO, PushTypeEnum.PAY_SHEET_ADD, dataList, corpid, payPlanSheetEntityExt, I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_ADD_TITLE), I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_ADD_CONTENT));
        } catch (XbbException e) {
            //回滚子单，流水(无流水的不需回滚)，付款计划，采购合同，预付款余额(未处理余额则无需回滚)
            Long customerId = dataList.getLongValue(PaySheetEnum.LINK_SUPPLIER.getAttr());
            addRollBack4LinkEs(corpid, sheetId, sonSheetList, flowFlag, paymentIds, contractIds, writeOffPrepaymentFlag, Collections.singletonList(customerId));
            throw e;
        } catch (Exception e) {
            //回滚子单，流水(无流水的不需回滚)，付款计划，采购合同，预付款余额(未处理余额则无需回滚)
            Long customerId = dataList.getLongValue(PaySheetEnum.LINK_SUPPLIER.getAttr());
            addRollBack4LinkEs(corpid, sheetId, sonSheetList, flowFlag, paymentIds, contractIds, writeOffPrepaymentFlag, Collections.singletonList(customerId));
            LOG.error("保存已核销付款单到数据库报错", e);
            throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208052, PaymentErrorCodeEnum.API_ERROR_208052.getMsg(), XbbRefTypeEnum.PAY_SHEET.getName());
        }
    }

    /**
     * 红冲已核销、红冲预付款核销
     * @param sheetTypeEnum 回/付款类型
     * @param payPlanSheetInsertDTO 保存dto
     * @param paasFormDataEntity 数据实体
     * @param paasFormEntityExt 表单form
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void redSave(SheetTypeEnum sheetTypeEnum, PayPlanSheetInsertDTO payPlanSheetInsertDTO, PaasFormDataEntity paasFormDataEntity, PaasFormEntityExt paasFormEntityExt) throws XbbException{
        /*
         红冲已核销、红冲预付款核销：付款金额，核销金额都为负，且一致
         */
        JSONObject dataList = payPlanSheetInsertDTO.getDataList();
        String corpid = payPlanSheetInsertDTO.getCorpid();
        String userId = payPlanSheetInsertDTO.getUserId();
        if (Objects.nonNull(payPlanSheetInsertDTO.getProcessCreatorId())) {
            userId = payPlanSheetInsertDTO.getProcessCreatorId();
        }
        JSONArray amountDetails = payPlanSheetInsertDTO.getAmountDetail();
        double allAmount = 0D;
        //付款计划和采购合同对应的付款金额
        Map<Long, Double> contractIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> paymentIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> contractIds = new HashSet<>();
        Set<Long> paymentIds = new HashSet<>();
        //付款单的红冲付款金额（此时还未处理成负数）
        Double sheetAmount = getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.AMOUNT.getAttr(), 0D);
        SheetAttrPojo sheetAttrPojo = new SheetAttrPojo(sheetTypeEnum.getXbbRefTypeEnum());
        //处理金额明细
        List<JSONObject> sonSheetDataList = saasSaveHelp.handleAmountDetail(payPlanSheetInsertDTO, sheetAmount, sheetTypeEnum, sheetAttrPojo, dataList, amountDetails, allAmount, contractIdToAmount, paymentIdToAmount, contractIds, paymentIds);
        Long linkPreId = FastJsonHelper.getLongFromFormData(dataList, PaySheetEnum.ORIGIN_ID.getAttr());
        //红冲要对原始付款单关联的已付/部分已付付款计划红冲，需要用前端传入的付款计划ids，否则需要自己查
        Double sumAmount = getSumAmount(payPlanSheetInsertDTO, contractIds, paymentIds, linkPreId);
        if (Arith.sub(sheetAmount , sumAmount) > ConfigConstant.amountAccuracy) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.DETAIL_BEYOND_AMOUNT_RED, PaySheetEnum.ORIGIN_ID.getAttrName());
        }
        //处理付款计划并封装要更新的结果：判断已付金额是否已经超过付款计划内的未付金额，并把付款计划的已付金额增加及更改其付款状态等
        List<UpdateDataEntity> updatePayList = payPlanService.handlePlan(sheetTypeEnum, dataList, corpid, paymentIdToAmount, paymentIds);
        //处理采购合同并封装要更新的结果：判断已付金额是否已经超过采购合同内的未付金额，并把采购合同的已付金额增加等
        List<UpdateDataEntity> updateConList = purchaseService.handleContract(sheetTypeEnum, corpid, contractIdToAmount, contractIds);
        PayPlanSheetEntityExt payPlanSheetEntityExt = new PayPlanSheetEntityExt();
        BeanUtil.copyProperties(paasFormDataEntity, payPlanSheetEntityExt);
        fundHelp.initSheetEntity4Save(userId, payPlanSheetEntityExt);
        for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPayPlanSheet().entrySet()){
            SaasDataInitHelp.antDataSet(dataList,entry.getKey(),entry.getValue());
        }
        long now = DateUtil.getNow();
        payPlanSheetEntityExt.setData(dataList);
        String uuid = UUID.randomUUID().toString();
        payPlanSheetEntityExt.setUuid(uuid);
        payPlanSheetEntityExt.setAddTime(now);
        payPlanSheetEntityExt.setUpdateTime(now);
        List<PayPlanSheetEntityExt> sonSheetList = null;
        Long sheetId = null;
        try {
            //插入父付款、子付款
            if (sonSheetDataList.size() > BasicConstant.ONE) {
                payPlanSheetEntityExt.setAlone(SheetAloneEnum.PARENT.getCode());
            } else {
                //没有明细，父子合并
                payPlanSheetEntityExt.setAlone(SheetAloneEnum.NORMAL.getCode());
            }
            payPlanSheetModel.save(payPlanSheetEntityExt);
            sheetId = payPlanSheetEntityExt.getId();
            paasFormDataEntity.setId(sheetId);
            sonSheetList = saasPaySheetHelper.saveSheetSon(corpid, sonSheetDataList, payPlanSheetEntityExt, uuid);
            //更新付款计划/合同
            saasPayPlanHelper.savePayPlan(corpid, updatePayList, "PayPlanSheetServiceImpl.redSave：新建红冲付款单更新付款计划时失败");
            purchaseHelp.savePurchase(corpid, updateConList, "PayPlanSheetServiceImpl.redSave：新建红冲付款单更新采购合同时失败");
            Long accountId = FastJsonHelper.getLongOrDefaultFromFormData(dataList, PaySheetEnum.FUND_ACCOUNT.getAttr(), 0L);
            Long addTime = payPlanSheetEntityExt.getAddTime();
            Long sheetTime = fundHelp.getSheetTime4FundFlow(dataList, PaySheetEnum.REAL_PAY_TIME.getAttr(), payPlanSheetInsertDTO.getExplainMap(), addTime);
            //账户余额变动 红冲金额未处理成负数
            payAndPaymentSheetHelp.saveByPaymentSheetOrPaySheet(accountId, sheetAmount, corpid);
            //流水表日志记录
            FundAccountFlowEntity fundAccountFlowEntity = new FundAccountFlowEntity(corpid, DateTimeUtil.getInt(), payPlanSheetEntityExt.getCreatorId(), FundAccountFlowTypeEnum.PAY_SHEET.getCode(), payPlanSheetEntityExt.getId(), accountId, sheetTime, sheetAmount);
            fundAccountFlowModel.insert(fundAccountFlowEntity);
            //处理付款单团队-必须在团队保存后执行，需要用到付款单的id
            handleSheetTeam(dataList, corpid, sheetTypeEnum, payPlanSheetEntityExt, sonSheetList);
            saasSaveHelp.sheetAddLog(payPlanSheetInsertDTO, corpid, userId, payPlanSheetEntityExt, XbbRefTypeEnum.PAY_SHEET.getName(), OperateModuleTypeEnum.PayManage);
            // 添加推送消息
            sheetAddMessage(payPlanSheetInsertDTO, PushTypeEnum.PAY_SHEET_RED_ADD, dataList, corpid, payPlanSheetEntityExt, I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_RED_ADD_TITLE), I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_RED_ADD_CONTENT));
        } catch (XbbException e) {
            //回滚子单，流水，付款计划，采购合同
            addRollBack4LinkEs(corpid, sheetId, sonSheetList, true, paymentIds, contractIds, false, null);
            throw e;
        } catch (Exception e) {
            //回滚子单，流水，付款计划，采购合同
            addRollBack4LinkEs(corpid, sheetId, sonSheetList, true, paymentIds, contractIds, false, null);
            LOG.error("保存红冲付款单到数据库报错", e);
            throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208052, PaymentErrorCodeEnum.API_ERROR_208052.getMsg(), XbbRefTypeEnum.PAY_SHEET.getName());
        }
    }

    /**
     * 预付款、红冲预付款余额
     * @param sheetTypeEnum 回/付款类型
     * @param payPlanSheetInsertDTO 保存dto
     * @param paasFormDataEntity 数据实体
     * @param paasFormEntityExt 表单form
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void prepaySave(SheetTypeEnum sheetTypeEnum, PayPlanSheetInsertDTO payPlanSheetInsertDTO, PaasFormDataEntity paasFormDataEntity, PaasFormEntityExt paasFormEntityExt) throws XbbException{
        /*
         预付款只关联了客户，其红冲也是如此，因此除了客户余额无需更新采购合同、付款计划
         预付款：只存付款金额，核销金额为空
         红冲预付款余额：只存付款金额、且为负，核销金额为空（需要把金额置为负数，并校验客户余额是否足够红冲）
         */
        JSONObject dataList = payPlanSheetInsertDTO.getDataList();
        String corpid = payPlanSheetInsertDTO.getCorpid();
        String userId = payPlanSheetInsertDTO.getUserId();
        if (Objects.nonNull(payPlanSheetInsertDTO.getProcessCreatorId())) {
            userId = payPlanSheetInsertDTO.getProcessCreatorId();
        }
        boolean redFlag = false;
        if (Objects.equals(sheetTypeEnum, SheetTypeEnum.RED_PREPAY)) {
            redFlag = true;
            Double amount = dataList.getDouble(PaySheetEnum.AMOUNT.getAttr());
            //检查红冲预付款余额的红冲金额是否小于客户余额
            checkBalance(dataList, corpid, amount);
            //金额置为负数
            dataList.put(PaySheetEnum.AMOUNT.getAttr(), Arith.mul(amount, -1));
        }
        PayPlanSheetEntityExt payPlanSheetEntityExt = new PayPlanSheetEntityExt();
        BeanUtil.copyProperties(paasFormDataEntity, payPlanSheetEntityExt);
        fundHelp.initSheetEntity4Save(userId, payPlanSheetEntityExt);
        for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPayPlanSheet().entrySet()){
            SaasDataInitHelp.antDataSet(dataList,entry.getKey(),entry.getValue());
        }
        long now = DateUtil.getNow();
        payPlanSheetEntityExt.setData(dataList);
        String uuid = UUID.randomUUID().toString();
        payPlanSheetEntityExt.setUuid(uuid);
        payPlanSheetEntityExt.setAlone(SheetAloneEnum.NORMAL.getCode());
        payPlanSheetEntityExt.setAddTime(now);
        payPlanSheetEntityExt.setUpdateTime(now);
        Long sheetId = null;
        Long supplierId = dataList.getLong(PaySheetEnum.LINK_SUPPLIER.getAttr());
        try {
            payPlanSheetModel.save(payPlanSheetEntityExt);
            sheetId = payPlanSheetEntityExt.getId();
            paasFormDataEntity.setId(sheetId);
            //添加预付款余额
            saasPaySheetHelper.saveBySheet(payPlanSheetEntityExt);
            Double amount = getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.AMOUNT.getAttr(), 0D);
            Long accountId = FastJsonHelper.getLongOrDefaultFromFormData(dataList, PaySheetEnum.FUND_ACCOUNT.getAttr(), 0L);
            Long addTime = payPlanSheetEntityExt.getAddTime();
            Long sheetTime = fundHelp.getSheetTime4FundFlow(dataList, PaySheetEnum.REAL_PAY_TIME.getAttr(), payPlanSheetInsertDTO.getExplainMap(), addTime);
            amount = Arith.mul(amount, -1);
            payAndPaymentSheetHelp.saveByPaymentSheetOrPaySheet(accountId, amount, corpid);
            //流水表日志记录
            FundAccountFlowEntity fundAccountFlowEntity = new FundAccountFlowEntity(corpid, DateTimeUtil.getInt(), payPlanSheetEntityExt.getCreatorId(), FundAccountFlowTypeEnum.PAY_SHEET.getCode(), payPlanSheetEntityExt.getId(), accountId, sheetTime, amount);
            fundAccountFlowModel.insert(fundAccountFlowEntity);
            //处理付款单团队-必须在团队保存后执行，需要用到付款单的id
            Map<Long, List<Long>> sheetIdAndDataIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> contractIdIn = new ArrayList<>();
            fundHelp.handleSheetIdAndCusIdMap(contractIdIn, sheetIdAndDataIdMap, payPlanSheetEntityExt, PaySheetEnum.LINK_SUPPLIER.getAttr());
            userTeamService.createPaySheetUser(corpid, supplierId, contractIdIn, sheetIdAndDataIdMap, sheetTypeEnum, false);
            saasSaveHelp.sheetAddLog(payPlanSheetInsertDTO, corpid, userId, payPlanSheetEntityExt, XbbRefTypeEnum.PAY_SHEET.getName(), OperateModuleTypeEnum.PayManage);
            // 添加推送消息
            PushTypeEnum pushTypeEnum;
            String pushTitle;
            String pushContent;
            if (redFlag) {
                pushTypeEnum = PushTypeEnum.PAY_SHEET_RED_PREPAY_ADD;
                pushTitle = I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_RED_PREPAY_ADD_TITLE);
                pushContent = I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_RED_PREPAY_ADD_CONTENT);
            } else {
                pushTypeEnum = PushTypeEnum.PAY_SHEET_PREPAY_ADD;
                pushTitle = I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_PREPAY_ADD_TITLE);
                pushContent = I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_PREPAY_ADD_CONTENT);
            }
            sheetAddMessage(payPlanSheetInsertDTO, pushTypeEnum, dataList, corpid, payPlanSheetEntityExt, pushTitle, pushContent);
        } catch (XbbException e) {
            //只回滚资金流水，预付款余额
            addRollBack4LinkEs(corpid, sheetId, null, true, null, null, true, Collections.singletonList(supplierId));
            throw e;
        } catch (Exception e) {
            //只回滚资金流水，预付款余额
            addRollBack4LinkEs(corpid, sheetId, null, true, null, null, true, Collections.singletonList(supplierId));
            LOG.error("保存付款单到数据库报错", e);
            throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208052, PaymentErrorCodeEnum.API_ERROR_208052.getMsg(), XbbRefTypeEnum.PAY_SHEET.getName());
        }
    }

    /**
     * 坏账保存
     * @param sheetTypeEnum 付/付款类型
     * @param payPlanSheetInsertDTO 保存dto
     * @param paasFormDataEntity 数据实体
     * @param paasFormEntityExt 表单form
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void badSave(SheetTypeEnum sheetTypeEnum, PayPlanSheetInsertDTO payPlanSheetInsertDTO, PaasFormDataEntity paasFormDataEntity, PaasFormEntityExt paasFormEntityExt) throws XbbException{
        /*
         坏账：付款金额，核销金额一致
         */
        JSONObject dataList = payPlanSheetInsertDTO.getDataList();
        String corpid = payPlanSheetInsertDTO.getCorpid();
        String userId = payPlanSheetInsertDTO.getUserId();
        if (Objects.nonNull(payPlanSheetInsertDTO.getProcessCreatorId())) {
            userId = payPlanSheetInsertDTO.getProcessCreatorId();
        }
        JSONArray amountDetails = payPlanSheetInsertDTO.getAmountDetail();
        double allAmount = 0D;
        //付款计划和合同对应的付款金额
        Map<Long, Double> contractIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> paymentIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> contractIds = new HashSet<>();
        Set<Long> paymentIds = new HashSet<>();
        //付款单的实际坏账金额
        Double sheetAmount = getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.AMOUNT.getAttr(), 0D);
        SheetAttrPojo sheetAttrPojo = new SheetAttrPojo(sheetTypeEnum.getXbbRefTypeEnum());
        //处理金额明细
        List<JSONObject> sonSheetDataList = saasSaveHelp.handleAmountDetail(payPlanSheetInsertDTO, sheetAmount, sheetTypeEnum, sheetAttrPojo, dataList, amountDetails, allAmount, contractIdToAmount, paymentIdToAmount, contractIds, paymentIds);
        Double sumAmount = getSumAmount(payPlanSheetInsertDTO, contractIds, paymentIds, null);
        if (Arith.sub(sheetAmount , sumAmount) > ConfigConstant.amountAccuracy) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.BAD_AMOUNT, StringUtil.formatDouble(sumAmount));
        }
        //处理付款计划并封装要更新的结果：判断已付金额是否已经超过付款计划内的未付金额，并把付款计划的已付金额增加及更改其付款状态等
        List<UpdateDataEntity> updatePayList = payPlanService.handlePlan(sheetTypeEnum, dataList, corpid, paymentIdToAmount, paymentIds);
        //处理采购合同并封装要更新的结果：判断已付金额是否已经超过采购合同内的未付金额，并把采购合同的已付金额增加等
        List<UpdateDataEntity> updateConList = purchaseService.handleContract(sheetTypeEnum, corpid, contractIdToAmount, contractIds);
        // 保存坏账付款单
        PayPlanSheetEntityExt payPlanSheetEntityExt = new PayPlanSheetEntityExt();
        BeanUtil.copyProperties(paasFormDataEntity, payPlanSheetEntityExt);
        fundHelp.initSheetEntity4Save(userId, payPlanSheetEntityExt);
        for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPayPlanSheet().entrySet()){
            SaasDataInitHelp.antDataSet(dataList,entry.getKey(),entry.getValue());
        }
        payPlanSheetEntityExt.setData(dataList);
        payPlanSheetEntityExt.setId(null);
        String uuid = UUID.randomUUID().toString();
        payPlanSheetEntityExt.setUuid(uuid);
        payPlanSheetEntityExt.setAddTime(DateUtil.getNow());
        payPlanSheetEntityExt.setUpdateTime(DateUtil.getNow());
        List<PayPlanSheetEntityExt> sonSheetList = null;
        Long sheetId = null;
        try {
            //插入父付款、子付款
            if (sonSheetDataList.size() > BasicConstant.ONE) {
                payPlanSheetEntityExt.setAlone(SheetAloneEnum.PARENT.getCode());
            } else {
                //没有明细，父子合并
                payPlanSheetEntityExt.setAlone(SheetAloneEnum.NORMAL.getCode());
            }
            payPlanSheetModel.save(payPlanSheetEntityExt);
            sheetId = payPlanSheetEntityExt.getId();
            //回滚ES 需要dataID
            paasFormDataEntity.setId(sheetId);
            sonSheetList = saasPaySheetHelper.saveSheetSon(corpid, sonSheetDataList, payPlanSheetEntityExt, uuid);
            //更新付款计划/合同
            saasPayPlanHelper.savePayPlan(corpid, updatePayList, "PayPlanSheetServiceImpl.badSave：新建坏账付款单更新付款计划时失败");
            purchaseHelp.savePurchase(corpid, updateConList, "PayPlanSheetServiceImpl.badSave：新建坏账付款单更新合同时失败");
            //处理付款单团队-必须在团队保存后执行，需要用到付款单的id
            handleSheetTeam(dataList, corpid, sheetTypeEnum, payPlanSheetEntityExt, sonSheetList);
            saasSaveHelp.sheetAddLog(payPlanSheetInsertDTO, corpid, userId, payPlanSheetEntityExt, "坏账" + XbbRefTypeEnum.PAY_SHEET.getName(), OperateModuleTypeEnum.PayManage);
            // 推送消息
            sheetAddMessage(payPlanSheetInsertDTO, PushTypeEnum.PAY_SHEET_BAD_ADD, dataList, corpid, payPlanSheetEntityExt, I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_BAD_ADD_TITLE), I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_BAD_ADD_CONTENT));
        } catch (XbbException e) {
            //回滚子单，付款计划，采购合同
            addRollBack4LinkEs(corpid, sheetId, sonSheetList, false, paymentIds, contractIds, false, null);
            throw e;
        } catch (Exception e) {
            //回滚子单，付款计划，采购合同
            addRollBack4LinkEs(corpid, sheetId, sonSheetList, false, paymentIds, contractIds, false, null);
            LOG.error("插入坏账付款单失败, e");
            throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208052, PaymentErrorCodeEnum.API_ERROR_208052.getMsg(), XbbRefTypeEnum.PAY_SHEET.getName());
        }
    }

    /**
     * 新建付款单失败，回滚关联业务的es数据
     * 回滚子单，流水(无流水的不需回滚)，付款计划，采购合同，预付款余额(未处理余额则无需回滚)
     * @param corpid 公司id
     * @param sheetId 付款单id（即新建的这条付款单id），当前该参数控制回滚流水数据
     * @param sonSheetList 子单
     * @param flowFlag 是否需要回滚资金流水es
     * @param planIdIn 关联付款计划id集合
     * @param purchaseIdIn 关联采购合同id集合
     * @param balanceFlag 是否需要回滚预付款余额es
     * @param supplierIdIn 供应商id集合
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void addRollBack4LinkEs(String corpid, Long sheetId, List<PayPlanSheetEntityExt> sonSheetList, boolean flowFlag, Collection<Long> planIdIn, Collection<Long> purchaseIdIn, boolean balanceFlag, Collection<Long> supplierIdIn) {
        //新建失败，回滚异步
        threadPoolBeanConfig.addUpdateDelThreadPool().execute(() -> {
            try{
                //回滚子付款单es--新增是直接物理删除es（主表和团队表数据在主流程内已经回滚）
                addRollbackList(sonSheetList, corpid);
                //回滚流水es-直接删除es，预收款核销不入流水，不用处理
                if (flowFlag) {
                    fundAccountFlowService.addRollback(corpid, FundAccountFlowTypeEnum.PAY_SHEET.getCode(), Collections.singletonList(sheetId));
                }
                /*
                 以下业务需要查数据库同步至es内，因此睡眠一小会，确保事务回滚完毕数据库恢复到操作之前的状态
                 */
                Thread.sleep(1000L);
                //被更新的关联业务es回滚至更改之前（通过查数据库）
                payPlanService.updateRollback(planIdIn, corpid);
                purchaseService.updateRollback(purchaseIdIn, corpid);
                //回滚预付款余额es-如果新增的预收款余额，则删除es；如果原是对原预收款余额修改，则读库同步至es
                if (balanceFlag) {
                    payBalanceService.updateRollbackBySupplierId(supplierIdIn, corpid);
                }
            } catch (XbbException | InterruptedException e1) {
                LOG.error("paySheet addRollBack4LinkEs rollback" + e1);
                // 恢复中断状态
                Thread.currentThread().interrupt();
            }
        });
    }

    /**
     * 付款单删除失败回滚es，同步数据库数据至es（需确保失败后数据库事务回滚结束才同步es）
     * @param corpid 公司id
     * @param allDelIdList 要删除的付款单id集合
     * @param planIdIn 关联付款计划id集合
     * @param purchaseIdIn 关联采购合同id集合
     * @param supplierIdSet 供应商id集合
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void delRollBack4LinkEs(String corpid, List<Long> allDelIdList, List<Long> planIdIn, List<Long> purchaseIdIn, Set<Long> supplierIdSet) {
        threadPoolBeanConfig.addUpdateDelThreadPool().execute(() -> {
            try{
                //需要查数据库同步至es内，因此睡眠一小会，确保事务回滚完毕数据库恢复到操作之前的状态
                Thread.sleep(1000L);
                //以下为同步数据库数据至es内：通过关联业务id，查询回滚后的数据库数据，同步至es内
                updateRollback(allDelIdList, corpid);
                //回滚资金流水、关联付款计划、关联采购合同、预付款余额
                fundAccountFlowService.updateRollback(corpid, FundAccountFlowTypeEnum.PAY_SHEET.getCode(), allDelIdList);
                payPlanService.updateRollback(planIdIn, corpid);
                purchaseService.updateRollback(purchaseIdIn, corpid);
                payBalanceService.updateRollbackBySupplierId(supplierIdSet, corpid);
            } catch (XbbException | InterruptedException e1) {
                LOG.error("paySheet delRollBack4LinkEs rollback" + e1);
                // 恢复中断状态
                Thread.currentThread().interrupt();
            }
        });
    }


    /**
     * 判断前端输入的预付款核销、红冲预付款余额类型付款单的金额是否超过供应商余额
     * @param dataList 付款单data
     * @param corpid 公司id
     * @param sheetAmount 付款单金额（红冲预付款余额的红冲金额、预付款核销的核销金额）
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void checkBalance(JSONObject dataList, String corpid, Double sheetAmount) throws XbbException {
        //预付款核销，要控制金额小于供应商余额
        Long supplierId = FastJsonHelper.getLongOrDefaultFromFormData(dataList, PaySheetEnum.LINK_SUPPLIER.getAttr(), 0L);
        PayBalanceEntity payBalanceEntity = payBalanceModel.getBySupplierId(supplierId, corpid);
        //如果供应商预付款余额不足，则不能保存成功
        boolean nonEmptyFlag = payBalanceEntity != null && payBalanceEntity.getAdvancePaymentBalance() != null;
        boolean over = nonEmptyFlag && Arith.sub(sheetAmount , payBalanceEntity.getAdvancePaymentBalance()) > ConfigConstant.amountAccuracy;
        if (over) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.DETAIL_BEYOND_BALANCE_PAY_RED);
        }
    }
    /**
     * 得到付款单可付款（可红冲、可坏账）金额
     * 付款、坏账：获取采购合同/付款计划的未付
     * 红冲：获取（红冲付款单关联的采购合同/付款计划的）已付
     * @param sheetSaveDTO 付款单保存dto
     * @param contractIds 创建的付款单关联的采购合同id集合
     * @param paymentIds 创建的付款单关联的付款id集合
     * @param linkPreId 关联原始付款单id
     * @return java.lang.Double
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private Double getSumAmount(SheetSaveDTO sheetSaveDTO, Set<Long> contractIds, Set<Long> paymentIds, Long linkPreId) throws XbbException {
        SheetAmountDetailGetDTO sheetAmountDetailGetDTO = new SheetAmountDetailGetDTO();
        BeanUtil.copyProperties(sheetSaveDTO, sheetAmountDetailGetDTO);
        sheetAmountDetailGetDTO.setDataIdList(new ArrayList<>(contractIds));
        //空的数组也作为筛选条件
        sheetAmountDetailGetDTO.setEmptyFilterFlag(true);
        sheetAmountDetailGetDTO.setPaymentIdList(new ArrayList<>(paymentIds));
        sheetAmountDetailGetDTO.setLinkPreId(linkPreId);
        SheetAmountDetailGetVO sheetAmountDetailGetVO = saasPayPlanHelper.payAmountDetailGet(true, sheetAmountDetailGetDTO);
        return sheetAmountDetailGetVO.getSumAmount();
    }


    /**
     * 批量保存回款单
     *
     * @param payPlanSheetDTO
     * @param paySheetTypeEnum
     * @param supplierId
     * @return
     * @throws XbbException
     */
    @Override
    public PayPlanSheetAmountVO addBatch(PayPlanSheetDTO payPlanSheetDTO, PaySheetTypeEnum paySheetTypeEnum, Long supplierId) throws XbbException {
        String loginUserName = payPlanSheetDTO.getLoginUserName();
        String corpid = payPlanSheetDTO.getCorpid();
        String userId = payPlanSheetDTO.getUserId();
        // 审批兼容
        if (payPlanSheetDTO.getProcessCreatorId() != null) {
            userId = payPlanSheetDTO.getProcessCreatorId();
            UserEntity userEntity = userModel.getByKeyIngoreDel(userId, corpid);
            loginUserName = userEntity.getName();
        }
        // TODO 文件柜未进行操作
        PayPlanSheetAmountVO paymentSheetAmountVO = new PayPlanSheetAmountVO();
        // 批量新增流水号集合
        List<AddMuchFieldPojo> addBatchList = payPlanSheetDTO.getAddBatchList();
        List<String> addBatchSerialNoList= new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 开启严控模式后生成流水号
        PaasFormExplainEntity formExplainEntity = paasFormExplainModel.getByFormId(payPlanSheetDTO.getFormId(), payPlanSheetDTO.getCorpid());
        if (Objects.isNull(formExplainEntity)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(formExplainEntity.getExplains(), null);
        FieldAttrEntity fieldAttrEntity = explainMap.get(PaymentEnum.PAYMENT_NO.getAttr());
        if (Objects.nonNull(fieldAttrEntity)) {
            FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
            BeanUtil.copyProperties(payPlanSheetDTO, formDataAddDTO);
            String serialNo = "";
            for (AddMuchFieldPojo addMuchFieldPojo : addBatchList) {
                if (Objects.equals(fieldAttrEntity.getStrictController(), BasicConstant.ONE) && StringUtil.isEmpty(addMuchFieldPojo.getSerialNo())) {
                    serialNo = saasSaveHelp.getSerialNo(serialNo, formDataAddDTO, corpid, fieldAttrEntity);
                    addMuchFieldPojo.setSerialNo(serialNo);
//                    addMuchFieldPojo.getData().put(PaySheetEnum.PAY_PLAN_NO.getAttr(), serialNo);
                }
                addBatchSerialNoList.add(addMuchFieldPojo.getSerialNo());
            }
        }
        String addBatchSerialNoStr = StringUtils.join(addBatchSerialNoList, "，");
        // 批量更新流水号集合
        List<AddMuchFieldPojo> updateBatchList = payPlanSheetDTO.getUpdateBatchList();
        // 批量删除流水号集合
        List<AddMuchFieldPojo> delBatchList = payPlanSheetDTO.getDelBatchList();

        try {
            PayPlanSheetInsertBatchByPurchaseVO payPlanSheetInsertBatchByPurchaseVO;
            PaasFormEntityExt paasFormEntityExt = paasFormModel.getByBusinessType(XbbRefTypeEnum.PAY_SHEET.getCode(), corpid);
            // 删除逻辑
            if (Objects.nonNull(delBatchList) && !delBatchList.isEmpty()) {
                List<Long> idList = new ArrayList<>();
                for (AddMuchFieldPojo item : delBatchList) {
                    idList.add(item.getId());
                }
                PayPlanSheetDeleteBatchDTO payPlanSheetDeleteBatchDTO = new PayPlanSheetDeleteBatchDTO();
                BeanUtil.copyProperties(payPlanSheetDTO, payPlanSheetDeleteBatchDTO);
                payPlanSheetDeleteBatchDTO.setIdIn(idList);
                PayPlanSheetDeleteBatchVO paymentSheetDeleteBatchVO = deleteBatch(payPlanSheetDeleteBatchDTO);
                if(Objects.isNull(paymentSheetDeleteBatchVO)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                }
                if (CollectionsUtil.isNotEmpty(idList)) {
                    List<UserTeamEntity> userTeamEntities = userTeamHelp.getUserTeamList(idList, corpid, XbbRefTypeEnum.PAY_SHEET.getCode(), false, null);
                    if (CollectionsUtil.isNotEmpty(userTeamEntities)) {
                        List<Long> userIdIn = userTeamEntities.stream().map(UserTeamEntity::getId).collect(Collectors.toList());
                        payPlanSheetUserModel.batchUpdateByUserIdIn(corpid, userIdIn, userTeamEntities, null, DelEnum.DELETE.getDel(),false);
                    }
                }
            }

            if(!Objects.equals(payPlanSheetDTO.getIsImport(), 1) && Objects.nonNull(paasFormEntityExt) && Objects.equals(paasFormEntityExt.getIsProcessForm(), 1)){
                Iterator<AddMuchFieldPojo> iterator = addBatchList.iterator();
                while (iterator.hasNext()) {
                    AddMuchFieldPojo addMuchFieldPojo = iterator.next();
                    StartProcessDTO startProcessDTO = new StartProcessDTO();
                    BeanUtil.copyProperties(payPlanSheetDTO, startProcessDTO, true);
                    BeanUtil.copyProperties(addMuchFieldPojo, startProcessDTO, true);
                    startProcessDTO.setFormId(paasFormEntityExt.getId());
                    startProcessDTO.setFormDataId(0L);
                    startProcessDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
                    startProcessDTO.setBusinessType(XbbRefTypeEnum.PAY_SHEET.getCode());
                    if (payPlanSheetDTO.getProcessCreatorId() == null) {
                        startProcessDTO.setCreatorId(payPlanSheetDTO.getUserId());
                    } else {
                        startProcessDTO.setCreatorId(payPlanSheetDTO.getProcessCreatorId());
                    }

                    StartProcessVO startProcessVO = processStartHelp.startProcess(startProcessDTO, null);
                    if (Objects.isNull(startProcessVO)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.START_PROCESS_ERROR);
                    }
                    Integer noApprovalRequired = startProcessVO.getNoApprovalRequired();
                    if ( !Objects.equals(noApprovalRequired, 1) ){
                        iterator.remove();
                    }
                }
            }

            // 插入数据
            if(Objects.nonNull(addBatchList) && !addBatchList.isEmpty()){
                PayPlanSheetInsertBatchByPurchaseDTO payPlanSheetInsertBatchByPurchaseDTO = new PayPlanSheetInsertBatchByPurchaseDTO();
                BeanUtil.copyProperties(payPlanSheetDTO, payPlanSheetInsertBatchByPurchaseDTO);
                payPlanSheetInsertBatchByPurchaseDTO.setDataList(addBatchList);
                payPlanSheetInsertBatchByPurchaseVO = insertBatch(paySheetTypeEnum,payPlanSheetInsertBatchByPurchaseDTO, payPlanSheetDTO.getParentNew(),userId, supplierId);
                paymentSheetAmountVO.setRealPayTotalAmount(payPlanSheetInsertBatchByPurchaseVO.getRealPaymentTotalAmount());
                // 记录日志
                List<PayPlanSheetEntityExt> insertList = payPlanSheetInsertBatchByPurchaseVO.getInsertList();
                if(insertList.size() > 1){
                    String memo = format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_BATCH_ADD_FORM_DETAIL), loginUserName, paySheetTypeEnum.getName(), insertList.size());
                    List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    InfoArrPojo infoArrPojo = new InfoArrPojo();
                    infoArrPojo.setTitle(PaySheetEnum.PAY_PLAN_NO.getAttrName());
                    infoArrPojo.setContent(addBatchSerialNoStr);
                    infoArrPojoList.add(infoArrPojo);
                    mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, loginUserName, OperateModuleTypeEnum.PayManage, OperateTypeEnum.NEW,
                            "", "", memo, payPlanSheetDTO.getHttpHeader());
                } else if (Objects.equals(insertList.size(), 1)){
                    String memo = format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_ADD_WORK), loginUserName, XbbRefTypeEnum.PAY_SHEET.getName(), addBatchSerialNoStr);
                    mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.PayManage, OperateTypeEnum.NEW,
                            insertList.get(0).getId().toString(), addBatchSerialNoStr, memo, payPlanSheetDTO.getHttpHeader());
                }
            }
            // TODO 这里应该有点问题
            if(!Objects.equals(payPlanSheetDTO.getIsImport(), 1) && Objects.nonNull(paasFormEntityExt) && Objects.equals(paasFormEntityExt.getIsProcessForm(), 1)){
                Iterator<AddMuchFieldPojo> iterator = updateBatchList.iterator();
                while (iterator.hasNext()) {
                    AddMuchFieldPojo addMuchFieldPojo = iterator.next();
                    PayPlanSheetEntityExt oldPaymentSheetEntityExt = payPlanSheetModel.getByKey(addMuchFieldPojo.getId(),corpid);
                    StartProcessDTO startProcessDTO = new StartProcessDTO();
                    BeanUtil.copyProperties(payPlanSheetDTO, startProcessDTO, true);
                    BeanUtil.copyProperties(addMuchFieldPojo, startProcessDTO, true);
                    startProcessDTO.setFormId(paasFormEntityExt.getId());
                    startProcessDTO.setFormDataId(addMuchFieldPojo.getId());
                    startProcessDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
                    startProcessDTO.setBusinessType(XbbRefTypeEnum.PAY_SHEET.getCode());
                    if (payPlanSheetDTO.getProcessCreatorId() == null) {
                        startProcessDTO.setCreatorId(payPlanSheetDTO.getUserId());
                    } else {
                        startProcessDTO.setCreatorId(payPlanSheetDTO.getProcessCreatorId());
                    }

                    StartProcessVO startProcessVO = processStartHelp.startProcess(startProcessDTO, oldPaymentSheetEntityExt);
                    if (Objects.isNull(startProcessVO)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.START_PROCESS_ERROR);
                    }
                    Integer noApprovalRequired = startProcessVO.getNoApprovalRequired();
                    if ( !Objects.equals(noApprovalRequired, 1) ){
                        iterator.remove();
                    }
                }
            }

            //更新数据
            if(Objects.nonNull(updateBatchList) && !updateBatchList.isEmpty()){
                PayPlanSheetUpdateBatchMuchFieldDTO paymentSheetUpdateBatchMuchFieldDTO = new PayPlanSheetUpdateBatchMuchFieldDTO();
                BeanUtil.copyProperties(payPlanSheetDTO, paymentSheetUpdateBatchMuchFieldDTO);
                paymentSheetUpdateBatchMuchFieldDTO.setDataList(updateBatchList);
                PayPlanSheetUpdateBatchMuchFieldVO payPlanSheetUpdateBatchMuchFieldVO = updateBatch(paySheetTypeEnum,paymentSheetUpdateBatchMuchFieldDTO, explainMap);
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("paySheetServiceImpl.addBatch回款出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return paymentSheetAmountVO;
    }


    @Override
    public PayPlanSheetAmountVO addBatchForWorkflow(PayPlanSheetDTO payPlanSheetDTO, PaySheetTypeEnum paySheetTypeEnum, Long supplierId) throws XbbException {
        String corpid = payPlanSheetDTO.getCorpid();
        String userId = payPlanSheetDTO.getProcessCreatorId();

        PayPlanSheetAmountVO paymentSheetAmountVO = new PayPlanSheetAmountVO();
        // 批量新增流水号集合
        List<AddMuchFieldPojo> addBatchList = payPlanSheetDTO.getAddBatchList();
        // 开启严控模式后生成流水号
        PaasFormExplainEntity formExplainEntity = paasFormExplainModel.getByFormId(payPlanSheetDTO.getFormId(), payPlanSheetDTO.getCorpid());
        if (Objects.isNull(formExplainEntity)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(formExplainEntity.getExplains(), null);
        FieldAttrEntity fieldAttrEntity = explainMap.get(PaymentEnum.PAYMENT_NO.getAttr());
        if (Objects.nonNull(fieldAttrEntity)) {
            FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
            BeanUtil.copyProperties(payPlanSheetDTO, formDataAddDTO);
            String serialNo = "";
            for (AddMuchFieldPojo addMuchFieldPojo : addBatchList) {
                if (Objects.equals(fieldAttrEntity.getStrictController(), BasicConstant.ONE) && StringUtil.isEmpty(addMuchFieldPojo.getSerialNo())) {
                    serialNo = saasSaveHelp.getSerialNo(serialNo, corpid, formDataAddDTO.getFormId(), fieldAttrEntity);
                    addMuchFieldPojo.setSerialNo(serialNo);
                }
            }
        }

        try {

            // 删除逻辑
            List<AddMuchFieldPojo> delBatchList = payPlanSheetDTO.getDelBatchList();
            if (CollectionsUtil.isNotEmpty(delBatchList)) {
                for (AddMuchFieldPojo addMuchFieldPojo : delBatchList) {
                    FormDataDeleteBatchDTO formDataDeleteBatchDTO = new FormDataDeleteBatchDTO();
                    formDataDeleteBatchDTO.setDataIdList(Collections.singletonList(addMuchFieldPojo.getId()));
                    formDataDeleteBatchDTO.setIsBusinessRule(0);
                    formDataDeleteBatchDTO.setCorpid(corpid);
                    formDataDeleteBatchDTO.setUserId(userId);
                    formDataDeleteBatchDTO.setPlatform(PlatFormEnum.INTERNAL.getValue());
                    formDataDeleteBatchDTO.setBusinessType(formExplainEntity.getBusinessType());
                    formDataDeleteBatchDTO.setFormId(formExplainEntity.getFormId());
                    formDataDeleteBatchDTO.setAppId(formExplainEntity.getAppId());
                    formDataDeleteBatchDTO.setMenuId(formExplainEntity.getMenuId());
                    formDataDeleteBatchDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
                    workflowOperatorDataService.delete(formDataDeleteBatchDTO);
                }
            }


            // 插入数据
            Double amount = 0.0D;
            if(CollectionsUtil.isNotEmpty(addBatchList)) {
                for (AddMuchFieldPojo addMuchFieldPojo : addBatchList) {
                    JSONObject data = addMuchFieldPojo.getData();
                    Double realPaymentAmount = FundHelp.getSheetAmount4PaymentSheet(data, paySheetTypeEnum.getCode());
                    amount = Arith.add(amount, realPaymentAmount);

                    FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
                    formDataAddDTO.setFromApproval(addMuchFieldPojo.getFromApproval());
                    formDataAddDTO.setAppId(formExplainEntity.getAppId());
                    formDataAddDTO.setFormId(formExplainEntity.getFormId());
                    formDataAddDTO.setMenuId(formExplainEntity.getMenuId());
                    formDataAddDTO.setSerialNo(addMuchFieldPojo.getSerialNo());
                    formDataAddDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
                    formDataAddDTO.setBusinessType(paySheetTypeEnum.getBusinessType());
                    formDataAddDTO.setSubBusinessType(paySheetTypeEnum.getBusinessType());
                    formDataAddDTO.setDataList(data);
                    formDataAddDTO.setIsBusinessRule(0);
                    formDataAddDTO.setCorpid(corpid);
                    formDataAddDTO.setUserId(userId);
                    formDataAddDTO.setPlatform(PlatFormEnum.INTERNAL.getValue());
                    JSONArray ownerJsonArray = data.getJSONArray(FieldTypeEnum.OWNERID.getAlias());
                    JSONArray coUserJsonArray = data.getJSONArray(FieldTypeEnum.COUSERID.getAlias());
                    if (Objects.nonNull(ownerJsonArray) && ownerJsonArray.size() > BasicConstant.ZERO) {
                        List<ReturnUserAndDepartmentPojo> ownerIds = ownerJsonArray.toJavaList(ReturnUserAndDepartmentPojo.class);
                        formDataAddDTO.setOwnerId(ownerIds);
                    }
                    if (Objects.nonNull(coUserJsonArray) && coUserJsonArray.size() > BasicConstant.ZERO) {
                        List<ReturnUserAndDepartmentPojo> couserIds = coUserJsonArray.toJavaList(ReturnUserAndDepartmentPojo.class);
                        formDataAddDTO.setCoUserId(couserIds);
                    }
                    workflowOperatorDataService.add(formDataAddDTO);
                }
            }
            paymentSheetAmountVO.setRealPayTotalAmount(amount);

            // 更新数据
            List<AddMuchFieldPojo> updateBatchList = payPlanSheetDTO.getUpdateBatchList();
            if(Objects.nonNull(updateBatchList) && !updateBatchList.isEmpty()){
                UserEntity userEntity = userModel.getByKeyIngoreDel(userId, corpid);
                UserVO userVO = new UserVO();
                BeanUtil.copyProperties(userEntity, userVO);
                for (AddMuchFieldPojo addMuchFieldPojo : updateBatchList) {
                    FormDataUpdateDTO formDataUpdateDTO = new FormDataUpdateDTO(formExplainEntity.getFormId(), formExplainEntity.getAppId(), formExplainEntity.getMenuId(), addMuchFieldPojo.getId(), addMuchFieldPojo.getData(), SaasMarkEnum.SAAS.getCode(), paySheetTypeEnum.getBusinessType(), paySheetTypeEnum.getBusinessType(), null, userVO, corpid, null, PlatFormEnum.INTERNAL.getValue());
                    workflowDataService.update(formDataUpdateDTO);
                }
            }
        } catch (Exception e) {
            LOG.error("com.xbongbong.saas.service.impl.PayPlanSheetServiceImpl.addBatchForWorkflow 回款出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return paymentSheetAmountVO;
    }

    public PayPlanSheetInsertBatchByPurchaseVO insertBatch(PaySheetTypeEnum paySheetTypeEnum, PayPlanSheetInsertBatchByPurchaseDTO payPlanSheetInsertBatchByPurchaseDTO, Boolean parentNew, String userId, Long supplierId) throws XbbException{
        PayPlanSheetInsertBatchByPurchaseVO payPlanSheetInsertBatchByPurchaseVO = new PayPlanSheetInsertBatchByPurchaseVO();
        try {
            long now = DateUtil.getInt();
            String corpid = payPlanSheetInsertBatchByPurchaseDTO.getCorpid();
            List<PayPlanSheetEntityExt> payPlanSheetEntityExtList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Double amount = 0.0D;
            //主要用于绑定付款单与团队的信息，只有编号是唯一值，所以编号-》团队
            Map<String, AddMuchFieldPojo> serialTeamMap = new HashMap<>();
            for ( AddMuchFieldPojo item : payPlanSheetInsertBatchByPurchaseDTO.getDataList() ) {
                PayPlanSheetEntityExt payPlanSheetEntityExt = new PayPlanSheetEntityExt();
                BeanUtil.copyProperties(item, payPlanSheetEntityExt);
                JSONObject data = item.getData();
                fundHelp.initSheetEntity4Save(userId, payPlanSheetEntityExt);
                for ( Map.Entry<String, Object> entry : SaasDataInitHelp.initPaymentSheet().entrySet() ) {
                    SaasDataInitHelp.antDataSet(data, entry.getKey(), entry.getValue());
                }
                fundHelp.removeNotInMapping(data);
                payPlanSheetEntityExt.setCorpid(corpid);
                payPlanSheetEntityExt.setAppId(payPlanSheetInsertBatchByPurchaseDTO.getAppId());
                payPlanSheetEntityExt.setMenuId(payPlanSheetInsertBatchByPurchaseDTO.getMenuId());
                payPlanSheetEntityExt.setFormId(payPlanSheetInsertBatchByPurchaseDTO.getFormId());
                payPlanSheetEntityExt.setCreatorId(payPlanSheetInsertBatchByPurchaseDTO.getUserId());

                payPlanSheetEntityExt.setAddTime(now);
                payPlanSheetEntityExt.setUpdateTime(now);
                payPlanSheetEntityExt.setData(data);
                if ( Objects.isNull(payPlanSheetEntityExt.getFlowStatus()) ){
                    payPlanSheetEntityExt.setFlowStatus(FlowStatusEnum.NOT_NEED_APPROVAL.getType());
                }
                payPlanSheetEntityExtList.add(payPlanSheetEntityExt);
                Double realPaymentAmount = FundHelp.getSheetAmount4PaySheet(data, paySheetTypeEnum.getCode());
                amount = Arith.add(amount, realPaymentAmount);
                serialTeamMap.put(item.getSerialNo(), item);
            }
            if ( Objects.equals(PaySheetTypeEnum.WRITE_OFF_PREPAY.getCode(), paySheetTypeEnum.getCode()) && amount > 0 ){
                PayBalanceEntity payBalanceEntity = payBalanceModel.getBySupplierId(supplierId,corpid);
                if ( payBalanceEntity == null || payBalanceEntity.getAdvancePayBalance() < amount ){
                    //todo chenshan2需要一个创建失败的消息推送
                    PushRefTypePojo.Options options = new PushRefTypePojo.Options();
                    MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, Arrays.asList(payPlanSheetInsertBatchByPurchaseDTO.getUserId()), Collections.singletonList(0L), 0, null, I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_ADD_FAIL_TITLE), I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_ADD_FAIL_CONTENT), null, options);
                    baseProducer.sendMessage(PushTypeEnum.PAY_SHEET_ADD, messageRabbitMqDTO);
                    throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208036, PaymentErrorCodeEnum.API_ERROR_208036.getMsg());
                }
                payBalanceEntity.setAdvancePayBalance(-amount);
                payBalanceModel.update(payBalanceEntity,false);
            }
            List<PayPlanSheetEntityExt>  payPlanSheetList = payPlanSheetModel.insertBatch(payPlanSheetEntityExtList);
            List<FundAccountFlowEntity> fundAccountFlowEntities = new ArrayList<>();
            Map<Long, Double> fundAccountToAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByBusinessType(XbbRefTypeEnum.PAY_SHEET.getCode(), corpid);
            Map<String, FieldAttrEntity> explainMap = paasFormExplainEntity == null ? null : ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), PaySheetEnum.REAL_PAY_TIME.getAttr());
            for (PayPlanSheetEntityExt payPlanSheetEntityExt : payPlanSheetEntityExtList) {
                JSONObject dataList = payPlanSheetEntityExt.getData();
                String sheetType = FastJsonHelper.getStringFromFormData(dataList, PaySheetEnum.PAY_SHEET_TYPE.getAttr());
                if (!Objects.equals(sheetType, PaySheetTypeEnum.BAD_PAY.getCode()) && !Objects.equals(sheetType, PaySheetTypeEnum.WRITE_OFF_PREPAY.getCode())) {
                    Long accountId = FastJsonHelper.getLongOrDefaultFromFormData(dataList, PaySheetEnum.FUND_ACCOUNT.getAttr(), 0L);
                    Long sheetTime = fundHelp.getSheetTime4FundFlow(dataList, PaySheetEnum.REAL_PAY_TIME.getAttr(), explainMap, now);
                    Double sheetAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.AMOUNT.getAttr(), 0D);
                    //账户余额变动 付款取反
                    sheetAmount = Arith.mul(sheetAmount, -1);
                    fundAccountToAmountMap.merge(accountId, sheetAmount, Arith::add);
                    //流水表日志记录
                    FundAccountFlowEntity fundAccountFlowEntity = new FundAccountFlowEntity(corpid, now, payPlanSheetEntityExt.getCreatorId(), FundAccountFlowTypeEnum.PAY_SHEET.getCode(), payPlanSheetEntityExt.getId(), accountId, sheetTime, sheetAmount);
                    fundAccountFlowEntities.add(fundAccountFlowEntity);
                }
            }
            if (fundAccountFlowEntities.size() > 0) {
                fundAccountFlowModel.insertBatch(fundAccountFlowEntities);
            }
            if (fundAccountToAmountMap.size() > 0) {
                fundAccountService.saveBatchByPaymentSheetOrPaySheet(fundAccountToAmountMap);
            }
            payPlanSheetInsertBatchByPurchaseVO.setRealPaymentTotalAmount(amount);
            payPlanSheetInsertBatchByPurchaseVO.setInsertList(payPlanSheetEntityExtList);

            List<Long> paymentIdList = new ArrayList<>();
            List<Long> purchaseIdIn = new ArrayList<>();
            Map<Long,List<Long>> idAndContractIdMap = new HashMap<>(payPlanSheetList.size());
            List<Long> purchaseIds = new ArrayList<>();
            for (PayPlanSheetEntityExt paymentEntityExt : payPlanSheetList){
                paymentIdList.add(paymentEntityExt.getId());
                JSONObject data =  paymentEntityExt.getData();
                JSONArray purchaseIdArr  = FastJsonHelper.getJsonArrFromFormData(data,PaySheetEnum.LINK_PURCHASE.getAttr());
                for ( Object purchaseId : purchaseIdArr ) {
                    if ( Objects.nonNull(purchaseId) ) {
                        Long purchaseIdIdLong = Long.valueOf(purchaseId.toString());
                        purchaseIdIn.add(purchaseIdIdLong);
                        purchaseIds.add(purchaseIdIdLong);
                    }
                }
                idAndContractIdMap.put(paymentEntityExt.getId(),purchaseIds);
            }
            teamDataHelp.savePaymentSheetBatchBusUserTeam(payPlanSheetList, serialTeamMap, payPlanSheetInsertBatchByPurchaseDTO.getLoginUser());
        }catch (XbbException e){
            LOG.error("paySheetServiceImpl.insertBatch关于新建采购合同时关联新建" + paySheetTypeEnum.getName() + "失败", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return payPlanSheetInsertBatchByPurchaseVO;
    }

    /**
     * 获取回款团队
     *
     * @param payPlanUserEntityList
     * @param paySheetId
     * @param entity
     * @param corpid
     */
    private void getPayPlanSheetSheetUserTeam(List<PayPlanSheetUserEntity> payPlanUserEntityList, Long paySheetId, ReturnUserAndDepartmentPojo entity, Integer isMain, String corpid) {
        PayPlanSheetUserEntity payPlanSheetUserEntity = new PayPlanSheetUserEntity();
        payPlanSheetUserEntity.setCorpid(corpid);
        payPlanSheetUserEntity.setIsMain(isMain);
        payPlanSheetUserEntity.setUserId(entity.getId().toString());
        payPlanSheetUserEntity.setUserName(entity.getName());
        payPlanSheetUserEntity.setId(null);
        payPlanSheetUserEntity.setDataId(paySheetId);
        payPlanUserEntityList.add(payPlanSheetUserEntity);
    }

    public PayPlanSheetUpdateBatchMuchFieldVO updateBatch(PaySheetTypeEnum paySheetTypeEnum, PayPlanSheetUpdateBatchMuchFieldDTO payPlanSheetUpdateBatchMuchFieldDTO, Map<String, FieldAttrEntity> explainMap) throws XbbException{
        PayPlanSheetUpdateBatchMuchFieldVO paymentSheetUpdateBatchMuchFieldVO = new PayPlanSheetUpdateBatchMuchFieldVO();
        // 批量更新流水号集合
        List<AddMuchFieldPojo> dataList = payPlanSheetUpdateBatchMuchFieldDTO.getDataList();
        List<String> updateBatchSerialNoList= new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        try{
            String corpid = payPlanSheetUpdateBatchMuchFieldDTO.getCorpid();
            Map<String, Object> map = BeanUtil.convertBean2Map(payPlanSheetUpdateBatchMuchFieldDTO, true);
            List<Long> idList = new ArrayList<>();

            List<PaasFormDataEntityExt> updateList = new ArrayList<>();
            Map<Long,AddMuchFieldPojo> dataMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            dataList.forEach((item)->{
                idList.add(item.getId());
                JSONObject jsonObject = item.getData();
                dataMap.put(item.getId(),item);
            });
            map.put("idIn", idList);
            map.put("del", DelEnum.NORMAL.getDel());
            List<PayPlanSheetEntityExt> list = payPlanSheetModel.findEntitys(map);
            List<Long> esDeleteList = new ArrayList<>();
            if (list == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
            } else {
                Set<Long> idSet = new HashSet<>();
                List<String> unableEditAttrList = PaySheetEnum.getUnableEditAttrList(false, null);
                for(PayPlanSheetEntityExt payPlanSheetEntityExt: list) {
                    updateBatchSerialNoList.add(payPlanSheetEntityExt.getSerialNo());
                    JSONObject dbData = payPlanSheetEntityExt.getData();
                    AddMuchFieldPojo addMuchFieldPojo = dataMap.getOrDefault(payPlanSheetEntityExt.getId(),new AddMuchFieldPojo());
                    for (Map.Entry<String,Object> entry : addMuchFieldPojo.getData().entrySet()){
                        //不允许编辑的字段里面没有这个字段
                        Boolean isEdit = !unableEditAttrList.contains(entry.getKey());
                        if ( isEdit ){
                            dbData.put(entry.getKey(),entry.getValue());
                        }
                    }
                    if (StringUtil.isNotEmpty(addMuchFieldPojo.getSerialNo())) {
                        payPlanSheetEntityExt.setSerialNo(addMuchFieldPojo.getSerialNo());
                    }
                    fundHelp.removeNotInMapping(dbData);
                    payPlanSheetEntityExt.setData(dbData);
                    updateList.add(payPlanSheetEntityExt);
                    idSet.add(payPlanSheetEntityExt.getId());
                }
                for(Long id : idList) {
                    if (!idSet.contains(id)) {
                        esDeleteList.add(id);
                    }
                }
            }
            // 删除数据库没有，但是es有的数据
            if (!esDeleteList.isEmpty()) {
                paasEsModel.deleteBatch(esDeleteList, corpid, DelEnum.DELETE.getDel(), IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET);
            }
            if (!updateList.isEmpty()) {
                payPlanSheetHelp.updateBatch(list,payPlanSheetUpdateBatchMuchFieldDTO.getCorpid(), explainMap);
            }

            // 记录日志
            String updateBatchSerialNoStr = StringUtils.join(updateBatchSerialNoList, "，");
            String userId = payPlanSheetUpdateBatchMuchFieldDTO.getUserId();
            String loginUserName = payPlanSheetUpdateBatchMuchFieldDTO.getLoginUserName();
            if ( dataList.size() > 1 ) {
                String memo = format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_BATCH_UPDATE_FORM_DETAIL), loginUserName, XbbRefTypeEnum.PAY_SHEET.getName(), dataList.size());
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(PaySheetEnum.PAY_PLAN_NO.getAttrName());
                infoArrPojo.setContent(updateBatchSerialNoStr);
                infoArrPojoList.add(infoArrPojo);
                mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, loginUserName, OperateModuleTypeEnum.PayManage, OperateTypeEnum.EDIT,
                        "", "", memo, payPlanSheetUpdateBatchMuchFieldDTO.getHttpHeader());
            } else if ( Objects.equals(dataList.size(), 1) ) {
                String memo = format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_WORK), loginUserName, XbbRefTypeEnum.PAY_SHEET.getName(), updateBatchSerialNoStr);
                mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.PayManage, OperateTypeEnum.EDIT,
                        dataList.get(0).getId().toString(), updateBatchSerialNoStr, memo, payPlanSheetUpdateBatchMuchFieldDTO.getHttpHeader());
            }
        }catch (XbbException e){
            LOG.error("payPlanSheetServiceImpl.updateBatch关于新建采购合同时关联修改" + paySheetTypeEnum.getName() + "失败", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return paymentSheetUpdateBatchMuchFieldVO;
    }

    @Override
    public PaySheetUpdateBatchVO updateAttrBatch(PaySheetUpdateBatchDTO paySheetUpdateBatchDTO) throws XbbException {
        PaySheetUpdateBatchVO paySheetUpdateBatchVO = new PaySheetUpdateBatchVO();
        try {
            String corpid = paySheetUpdateBatchDTO.getCorpid();
            List<PaySheetUpdateDTO> paySheetList = paySheetUpdateBatchDTO.getPaySheetUpdateList();
            if (Objects.nonNull(paySheetList)
                    && !paySheetList.isEmpty()) {
                List<UpdateDataEntity> list = new ArrayList<>();
                paySheetList.forEach((item) -> {
                    list.add(ExplainUtil.getUpdateData(item.getId(), item.getData(), corpid));
                });
                if (!list.isEmpty()) {
                    payPlanSheetModel.updateBatch(list, corpid);
                }
            }
        } catch (Exception e) {
            LOG.error("PayPlanSheetServiceImpl.updateAttrBatch 批量更新出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return paySheetUpdateBatchVO;
    }

    @Override
    public PaySheetUpdateBatchVO updateAttrBatch(PaySheetUpdateBatchDTO paySheetUpdateBatchDTO, boolean needThrow) throws XbbException {
        PaySheetUpdateBatchVO paySheetUpdateBatchVO = new PaySheetUpdateBatchVO();
        try {
            String corpid = paySheetUpdateBatchDTO.getCorpid();
            List<PaySheetUpdateDTO> paySheetList = paySheetUpdateBatchDTO.getPaySheetUpdateList();
            if (Objects.nonNull(paySheetList)
                    && !paySheetList.isEmpty()) {
                List<UpdateDataEntity> list = new ArrayList<>();
                paySheetList.forEach((item) -> {
                    list.add(ExplainUtil.getUpdateData(item.getId(), item.getData(), corpid));
                });
                if (!list.isEmpty()) {
                    payPlanSheetModel.updateBatch(list, corpid, needThrow);
                }
            }
        } catch (Exception e) {
            LOG.error("PayPlanSheetServiceImpl.updateAttrBatch 批量更新出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return paySheetUpdateBatchVO;
    }

    @Override
    public void batchEditAttr(PaySheetEditAttrUpdateDTO paySheetEditAttrUpdateDTO) throws XbbException {
        try {
            List<PaySheetUpdateDTO> paySheetUpdateList =new ArrayList<>();
            List<Long> dataIdList = paySheetEditAttrUpdateDTO.getDataIdList();
            //预付款核销无自定义字段，需要排除
            String corpid = paySheetEditAttrUpdateDTO.getCorpid();
            List<String> fieldList = Arrays.asList("id", "flowStatus", PaySheetEnum.PAY_PLAN_NO.getAttr(), PaySheetEnum.getAttrConnectData(PaySheetEnum.PAY_SHEET_TYPE), FieldTypeEnum.SHEET_ALONE.getAlias());
            List<PaasFormDataEntityExt> paySheetEntityList = formHelp.getFormListByIds4All(corpid, IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, dataIdList, fieldList);
            if (Objects.isNull(paySheetEntityList)){
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
            }
            //权限团队校验前置了
            List<Long> errorIdList = new ArrayList<>();
//            List<Long> errorIdList = userTeamHelp.batchTeamMembersCheckEditPermission(paySheetEditAttrUpdateDTO.getBusinessType(), paySheetEditAttrUpdateDTO.getSaasMark(),
//                    paySheetEditAttrUpdateDTO.getMenuId(), paySheetEditAttrUpdateDTO.getLoginUser(), paySheetEditAttrUpdateDTO.getDistributorMark(),
//                    paySheetEditAttrUpdateDTO.getDataIdList(), new HashMap<>());
            List<String> errorNameList = new ArrayList<>();
            for (PaasFormDataEntityExt paasFormDataEntityExt : paySheetEntityList) {
                if (errorIdList.contains(paasFormDataEntityExt.getId())) {
                    errorNameList.add(paasFormDataEntityExt.getSerialNo());
                }
            }
            String nameStr = org.apache.commons.lang.StringUtils.join(errorNameList, "、");
            if (CollectionUtils.isNotEmpty(errorNameList)) {
                throw new XbbException(UserTeamErrorCodeEnum.API_ERROR_271038.getCode(), String.format(UserTeamErrorCodeEnum.API_ERROR_271038.getMsg(), nameStr));
            }

            Boolean isFieldDependence = paySheetEditAttrUpdateDTO.getIsFieldDependence();
            AttrValuePojo singleAttrValuePojo = ProSaveHelp.getSingleAttrValuePojo(isFieldDependence, paySheetEditAttrUpdateDTO.getFieldEditedList());
            String attr = singleAttrValuePojo.getAttr();
            List<String> allAttr = PaySheetEnum.getAllAttr();
            //true扩展的自定义字段（PaySheetEnum不包含的字段），false非自定义字段（PaySheetEnum内包含的字段）
            // 注：字段依赖的四个字段，是PaySheetEnum不包含的字段
            boolean redundantFlag = !allAttr.contains(attr);
            // 批量编辑日志
            List<String> updataItemList = new ArrayList<>(paySheetEntityList.size());
            List<Long> idList = new ArrayList<>(paySheetEntityList.size());
            for (PaasFormDataEntityExt entityExt : paySheetEntityList) {
                Long id = entityExt.getId();
                JSONObject data = entityExt.getData();
                if (data == null) {
                    continue;
                }
                String type = data.getString(PaySheetEnum.PAY_SHEET_TYPE.getAttr());
                //预付款核销无自定义字段，批量编辑时需要跳过自定义字段的批量设置
                if (Objects.equals(type, PaySheetTypeEnum.WRITE_OFF_PREPAY.getCode()) && redundantFlag) {
                    continue;
                }
                //付款单批量编辑支付方式排除红冲预付款余额和合并付款
                Integer alone = entityExt.getAlone();
                boolean ifEditPayMethod = Objects.equals(PaySheetEnum.PAY_TYPE.getAttr(), attr) && (Objects.equals(PaySheetTypeEnum.RED_PREPAY.getCode(), type) || Objects.equals(SheetAloneEnum.PARENT.getCode(), alone));
                if (ifEditPayMethod) {
                    continue;
                }
                idList.add(id);
                updataItemList.add(entityExt.getSerialNo());
                PaySheetUpdateDTO sheetUpdateDTO = new PaySheetUpdateDTO();
                sheetUpdateDTO.setId(id);
                JSONObject updateData = ProSaveHelp.getBatchUpdateData(paySheetEditAttrUpdateDTO.getFieldEditedList());
                sheetUpdateDTO.setData(updateData);
                paySheetUpdateList.add(sheetUpdateDTO);
            }
            if (!paySheetUpdateList.isEmpty()) {
                PaySheetUpdateBatchDTO paySheetUpdateBatchDTO = new PaySheetUpdateBatchDTO();
                BeanUtil.copyProperties(paySheetEditAttrUpdateDTO, paySheetUpdateBatchDTO);
                paySheetUpdateBatchDTO.setPaySheetUpdateList(paySheetUpdateList);
                updateAttrBatch(paySheetUpdateBatchDTO);

                String updataItem = StringUtils.join(updataItemList, "，");
                String userId = paySheetEditAttrUpdateDTO.getUserId();
                String loginUserName = paySheetEditAttrUpdateDTO.getLoginUserName();
                // 标签特殊处理
                Integer fieldType = paySheetEditAttrUpdateDTO.getFieldType();
                logHelp.analysisLabel(corpid, fieldType, isFieldDependence,paySheetEditAttrUpdateDTO.getLogFieldEditedList());

                String changedLogItemsStr = logHandleHelp.getChangedLogItemsStr(paySheetEditAttrUpdateDTO.getLogFieldEditedList());
                if(idList.size() > 1 ){
                    String memo = format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_FORM_DATA_BATCH_ATTR), loginUserName, XbbRefTypeEnum.PAY_SHEET.getName(), changedLogItemsStr, idList.size());
                    List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    InfoArrPojo infoArrPojo = new InfoArrPojo();
                    infoArrPojo.setTitle(XbbRefTypeEnum.PAY_SHEET.getName());
                    infoArrPojo.setContent(updataItem);
                    infoArrPojoList.add(infoArrPojo);
                    mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, loginUserName, OperateModuleTypeEnum.PayManage, OperateTypeEnum.EDIT, "", "", memo, paySheetEditAttrUpdateDTO.getHttpHeader());
                } else if (Objects.equals(idList.size(), 1)){
                    String memo = format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_FORM_DATA_ATTR), loginUserName, XbbRefTypeEnum.PAY_SHEET.getName(), updataItem, changedLogItemsStr);
                    mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.PayManage, OperateTypeEnum.EDIT, idList.get(0).toString(), updataItem, memo, paySheetEditAttrUpdateDTO.getHttpHeader());
                }
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("PayPlanSheetServiceImpl.batchEditAttr 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public ListAppVO formatPaySheetAppList(FormDataListDTO formDataListDTO, List<PaasFormDataEntityExt> esEntities, Integer totalCount) throws XbbException {
        List<AppListPojo> appListPojos = new ArrayList<>();
        for (PaasFormDataEntityExt paySheet : esEntities) {
            JSONObject data = paySheet.getData();
            Long paySheetId = paySheet.getId();
            Long appId = paySheet.getAppId();
            Long menuId = paySheet.getMenuId();
            Long formId = paySheet.getFormId();
            List<FormTitlePoJo> titleList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.TITLE_LIST, new JSONArray()).toJavaList(FormTitlePoJo.class);
            List<SummaryDataPoJo> summaryList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.SUMMARY_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            List<SummaryDataPoJo> lablesList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.LABELS_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            JSONObject others = disposePaySheetOthers(data);
            JSONObject superScript = new JSONObject();

            //app系统关联数据展示需要 others 和 superScript
            data.put("others",others);
            data.put("superScript",superScript);
            appListPojos.add(new AppListPojo(paySheetId, titleList, summaryList, superScript, lablesList, others, appId, menuId, formId));
        }
        ListAppVO listAppVO = new ListAppVO();
        listAppVO.setList(appListPojos);
        listAppVO.setTotalCount(totalCount);
        return listAppVO;
    }

    @Override
    public FormDataAddDTO formatExcelValue(ImportFormDataDTO importFormDataDTO, List<CellTitlePojo> titlePojoList, RowGroupPojo rowGroupPojo, List<FieldAttrEntityForImport> fieldAttrList) throws XbbException {
        FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
        BeanUtil.copyProperties(importFormDataDTO, formDataAddDTO);
        // data 数据
        JSONObject dataJson = new JSONObject();
        Long linkSupplierId = 0L;
        List<List<CellValuePojo>> rowValueList = rowGroupPojo.getRowValueList();
        // 分组的第一条数据作为给实体对象赋值的数据
        List<CellValuePojo> cellValueList = rowValueList.get(0);
        // 遍历数据
        for ( FieldAttrEntityForImport fieldAttrEntityForImport : fieldAttrList ) {
            String attr = fieldAttrEntityForImport.getAttr();
            Integer fieldType = fieldAttrEntityForImport.getFieldType();
            String attrName = fieldAttrEntityForImport.getAttrName();
            Integer columnIndex = importHelper.getColumnIndexByTitle(titlePojoList, attrName, null);
            Object cellValue = importHelper.getValueByColumnIndex(cellValueList, columnIndex);
            if (Objects.equals(attr, PaySheetEnum.LINK_SUPPLIER.getAttr())) {
                // 关联供应商根据linkedType判断
                linkSupplierId = importHelper.formatSuppplier2SupplierId(cellValue.toString(), dataJson, fieldAttrEntityForImport);
                if ( Objects.equals(linkSupplierId, 0L) ) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PLEASE_ENTER, fieldAttrEntityForImport.getAttrName());
                }
            } else if ( Objects.equals(fieldType, FieldTypeEnum.SUB_FORM.getType()) ) {
                importHelper.formatSubFormValue4Import(rowValueList, titlePojoList, importFormDataDTO, fieldAttrEntityForImport, dataJson);
            } else if (Objects.equals(fieldType, FieldTypeEnum.SERIALNO.getType())) {
                formDataAddDTO.setSerialNo(cellValue.toString());
            } else {
                if ( Objects.isNull(cellValue) || StringUtil.isEmpty(cellValue.toString()) ) {
                    continue;
                }
                if ( ImportHelper.commonHandleFieldType.contains(fieldAttrEntityForImport.getFieldType()) ) {
                    importHelper.formatCommonField(dataJson, fieldAttrEntityForImport, cellValue);
                } else if (Objects.equals(attr, PaySheetEnum.LINK_PURCHASE.getAttr()) ) {
                    importHelper.formatMultiRelyBusiness(linkSupplierId, dataJson, fieldAttrEntityForImport, cellValue, PurchaseEnum.SUPPLIER_ID.getAttr());
                } else if (Objects.equals(attr, PaySheetEnum.PAY_PLAN.getAttr())) {
                    importHelper.formatMultiRelyBusiness(linkSupplierId, dataJson, fieldAttrEntityForImport, cellValue, PayPlanEnum.LINK_SUPPLIER.getAttr());
                } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA.getType())) {
                    importHelper.formatLinkData(cellValue, fieldAttrEntityForImport, dataJson);
                } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA_MULTI.getType())) {
                    importHelper.formatLinkDataMulti(cellValue, importFormDataDTO, fieldAttrEntityForImport, dataJson);
                } else {
                    dataJson.put(attr, cellValue);
                }
            }
        }
        formDataAddDTO.setDataList(dataJson);
        return formDataAddDTO;
    }

    @Override
    public Map<Long, Double> sumRedAmountByPaySheetIdIn(String corpid, List<Long> sheetIdIn) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = saasPaySheetHelper.getBoolQueryBuilder4LinkRed(corpid, sheetIdIn);
        String amountAttr = StringConstant.JSON_DATA + StringConstant.POINT + PaySheetEnum.AMOUNT.getAttr();
        String redSheetAttr = StringConstant.JSON_DATA + StringConstant.POINT + PaySheetEnum.ORIGIN_ID.getAttr();
        List<String> fieldList = Arrays.asList(amountAttr, redSheetAttr);
        //分页查询
        XbbAggregatedPage<PaasFormDataEntityExt> esEntities = esHelper.findByPage(IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, boolQueryBuilder, PaasFormDataEntityExt.class, fieldList, BasicConstant.ONE, EsNormalConstant.FIND_NUM, null);
        List<PaasFormDataEntityExt> results = new ArrayList<>();
        if (esEntities != null) {
            results = esEntities.getContent();
        }
        Map<Long, Double> sheetIdInToRedAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        results.forEach(e -> {
            JSONObject data = e.getData();
            Long dataId = data.getLong(PaySheetEnum.ORIGIN_ID.getAttr());
            Double amount = sheetIdInToRedAmount.getOrDefault(dataId, 0D);
            amount = Arith.add(amount, data.getDouble(PaySheetEnum.AMOUNT.getAttr()));
            sheetIdInToRedAmount.put(dataId, amount);
        });
        return sheetIdInToRedAmount;
    }

    /**
     * 为新建已核销、预付款核销、红冲已核销、红冲预付款核销、坏账5种类型，及新建预收款、红冲预收款余额2种，总计7种类型付款单增加项目日志、消息推送
     * @param sheetSaveDTO 回/付款单保存dto
     * @param pushTypeEnum 推送类型枚举
     * @param dataList 付款单data
     * @param corpid 公司id
     * @param paySheetEntityExt 付款单实体
     * @param pushTitle 推送标题 @see
     * @param pushContent 推送内容 @see
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void sheetAddMessage(SheetSaveDTO sheetSaveDTO, PushTypeEnum pushTypeEnum, JSONObject dataList, String corpid, PaasFormDataEntity paySheetEntityExt, String pushTitle, String pushContent) throws XbbException {
        String replaceStr = "";
        if (Objects.equals(PushTypeEnum.PAY_SHEET_PREPAY_ADD, pushTypeEnum) || Objects.equals(PushTypeEnum.PAY_SHEET_RED_PREPAY_ADD, pushTypeEnum)) {
            //新建预收款、红冲预收款余额读取供应商名称
            replaceStr = dataList.getString(PaySheetEnum.SUPPLIER_LINK_TEXT.getAttr());
        } else {
            JSONArray purchaseNoArr = dataList.getJSONArray(PaySheetEnum.PURCHASE_LINK_TEXT.getAttr());
            List<String> purchaseNoList = purchaseNoArr == null ? new ArrayList<>() : purchaseNoArr.toJavaList(String.class);
            //逗号分隔的采购合同编号字符串
            replaceStr = join(SymbolConstant.COMMA_ENGLISH, purchaseNoList);
        }
        // 付款单创建消息推送
        Long dataId = paySheetEntityExt.getId();
        UserEntity userEntity = userModel.getByKeyIngoreDel(paySheetEntityExt.getCreatorId(), corpid);
        if (Objects.nonNull(userEntity)) {
            List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, pushTypeEnum.getCode(), pushTypeEnum.getSubCode(), userEntity, paySheetEntityExt);
            PushRefTypePojo.Options options = new PushRefTypePojo.Options(paySheetEntityExt.getAppId(), paySheetEntityExt.getMenuId(), paySheetEntityExt.getFormId(), dataId, Collections.singletonList(dataId), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.PAY_SHEET.getCode(), XbbRefTypeEnum.PAY_SHEET.getCode());
            MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, pushUserList, Collections.singletonList(dataId), 0, null, pushTitle, format(pushContent, userEntity.getName(), replaceStr), null, options);
            baseProducer.sendMessage(pushTypeEnum, messageRabbitMqDTO);
        }
    }

    /**
     * 批量获取用户下的红冲预收款和预收款回款单
     *
     * @param corpid
     * @param supplierIds
     * @param typeList
     * @return
     * @throws XbbException
     */
    @Override
    public List<PaasFormDataEntityExt> getPaymentSheetEsDataListBySupplierIds(String corpid, List<Long> supplierIds, List<String> typeList) throws XbbException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termsQuery(PaySheetEnum.getAttrConnectData(PaySheetEnum.LINK_SUPPLIER), supplierIds));
        boolQueryBuilder.filter(termQuery("del", 0));
        boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        boolQueryBuilder.filter(termsQuery("data." + PaySheetEnum.PAY_SHEET_TYPE.getAttr(), typeList));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET.getType()));
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET.getIndex());
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 0, PaasConstant.ES_MAX_PAGE_SIZE);
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, PaasFormDataEntityExt.class);
        return esEntities.getContent();
    }

    /**
     * 统计该类型的金额
     *
     * @param corpid
     * @param sheetId
     * @param codeList
     * @return
     * @throws XbbException
     */
    @Override
    public double sumAmountBySheet(String corpid, Long sheetId, List<String> codeList) throws XbbException {
        // 查询该付款计划下面关联的所有付款单(因为这个redsheet没有约定好，这里需要重复查询)
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        //限制alone
        boolQueryBuilder.filter(termsQuery(FieldTypeEnum.SHEET_ALONE.getAlias(), SheetAloneEnum.getNotParentCodeList()));
        boolQueryBuilder.filter(termsQuery(PaySheetEnum.getAttrConnectData(PaySheetEnum.PAY_PLAN), Arrays.asList(sheetId)));
        boolQueryBuilder.filter(termsQuery(PaySheetEnum.getEsAttr4Keyword(PaySheetEnum.PAY_SHEET_TYPE), codeList));
        return systemChartHelp.getDouble4Total(IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, boolQueryBuilder, PaySheetEnum.getAttrConnectData(PaySheetEnum.AMOUNT));
    }

    @Override
    public void dataConsistencyUpdateSupplier(String corpid, Long supplierId, String supplierName) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery("data." + PaySheetEnum.LINK_SUPPLIER.getAttr(), supplierId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<PayPlanSheetEntityExt> sheetList = payPlanSheetModel.findEntitys(param);
            if (Objects.nonNull(sheetList) && !sheetList.isEmpty()) {
                List<PaySheetUpdateDTO> sheetUpdateDTOList = new ArrayList<>();
                for (PayPlanSheetEntityExt entityExt : sheetList) {
                    PaySheetUpdateDTO sheetUpdateDTO = new PaySheetUpdateDTO();
                    sheetUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(PaySheetEnum.SUPPLIER_LINK_TEXT.getAttr(), supplierName);
                    sheetUpdateDTO.setData(data);
                    sheetUpdateDTOList.add(sheetUpdateDTO);
                }
                PaySheetUpdateBatchDTO sheetUpdateBatchDTO = new PaySheetUpdateBatchDTO();
                sheetUpdateBatchDTO.setCorpid(corpid);
                sheetUpdateBatchDTO.setPaySheetUpdateList(sheetUpdateDTOList);
                updateAttrBatch(sheetUpdateBatchDTO);
            }

        } catch (Exception e) {
            LOG.error("PayPlanSheetServiceImpl.dataConsistencyUpdateSupplier 出错，corpid=" + corpid + "  supplierId=" + supplierId + " supplierName=" + supplierName, e);
        }
    }

    @Override
    public void dataConsistencyUpdatePurchase(String corpid, Long purchaseId, String serialNo) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery("data." + PaySheetEnum.LINK_PURCHASE.getAttr(), purchaseId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYMENT_SHEET, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("corpid", corpid);
            params.put("idIn", ids);
            params.put("del", 0);
            List<PayPlanSheetEntityExt> sheetList = payPlanSheetModel.findEntitys(params);
            if (Objects.nonNull(sheetList) && !sheetList.isEmpty()) {
                List<PaySheetUpdateDTO> sheetUpdateDTOList = new ArrayList<>();
                for (PayPlanSheetEntityExt entityExt : sheetList) {
                    JSONObject oldData = entityExt.getData();
                    if (oldData == null) {
                        continue;
                    }
                    List<Long> idList = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData, PaySheetEnum.LINK_PURCHASE.getAttr(), new JSONArray()).toJavaList(Long.class);
                    List<String> noList = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData, PaySheetEnum.PURCHASE_LINK_TEXT.getAttr(), new JSONArray()).toJavaList(String.class);
                    for (int i = 0; i < idList.size(); i++) {
                        Long cid = idList.get(i);
                        if (Objects.equals(cid, purchaseId)) {
                            noList.set(i, serialNo);
                        }
                    }

                    PaySheetUpdateDTO sheetUpdateDTO = new PaySheetUpdateDTO();
                    sheetUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(PaySheetEnum.PURCHASE_LINK_TEXT.getAttr(), noList);
                    sheetUpdateDTO.setData(data);
                    sheetUpdateDTOList.add(sheetUpdateDTO);
                }
                PaySheetUpdateBatchDTO sheetUpdateBatchDTO = new PaySheetUpdateBatchDTO();
                sheetUpdateBatchDTO.setCorpid(corpid);
                sheetUpdateBatchDTO.setPaySheetUpdateList(sheetUpdateDTOList);
                updateAttrBatch(sheetUpdateBatchDTO);
            }
        } catch (Exception e) {
            LOG.error("PayPlanSheetServiceImpl.dataConsistencyUpdatePurchase fail， corpid=" + corpid + " purchaseId=" + purchaseId + "  purchaseNo=" + serialNo, e);
        }
    }

    @Override
    public void updateBatchLabelAttr(AddLabelDTO addLabelDTO, List<PaasFormDataEntityExt> addBatchList, Boolean addOrDelete) throws XbbException {
        PaySheetUpdateBatchDTO paySheetUpdateBatchDTO = new PaySheetUpdateBatchDTO();
        BeanUtil.copyProperties(addLabelDTO, paySheetUpdateBatchDTO);
        List<PaySheetUpdateDTO> paySheetList = new ArrayList<>();
        addBatchList.forEach(item->{
            PaySheetUpdateDTO paySheetUpdateDTO= new PaySheetUpdateDTO();
            paySheetUpdateDTO.setData(item.getData());
            paySheetUpdateDTO.setId(item.getId());
            paySheetList.add(paySheetUpdateDTO);
        });
        paySheetUpdateBatchDTO.setPaySheetUpdateList(paySheetList);
        updateAttrBatch(paySheetUpdateBatchDTO);

    }

    /**
     * 付款单普通流程保存之后的操作
     *
     * @param saasFormSaveDTO saas保存数据
     * @throws XbbException
     */
    @Override
    public void afterSave(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        Integer businessType = saasFormSaveDTO.getBusinessType();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        SheetTypeEnum sheetTypeEnum = SheetTypeEnum.getByBusinessType(businessType);
        if (Objects.equals(sheetTypeEnum, SheetTypeEnum.WRITE_OFF_PAY)) {
            //已核销
            writeOffAfterSave(saasFormSaveDTO);
        } else if (Objects.equals(sheetTypeEnum, SheetTypeEnum.WRITE_OFF_PREPAY)) {
            //预付款核销
            writeOffAfterSave(saasFormSaveDTO);
        } else if (Objects.equals(sheetTypeEnum, SheetTypeEnum.RED_WRITE_OFF_PAY)) {
            //红冲已核销
            redAfterSave(saasFormSaveDTO);
        } else if (Objects.equals(sheetTypeEnum, SheetTypeEnum.RED_WRITE_OFF_PREPAY)) {
            //红冲预付款核销
            redAfterSave(saasFormSaveDTO);
        } else if (Objects.equals(sheetTypeEnum, SheetTypeEnum.PREPAY)) {
            //预付款
            prepayAfterSave(saasFormSaveDTO);
        } else if (Objects.equals(sheetTypeEnum, SheetTypeEnum.RED_PREPAY)) {
            //红冲预付款余额
            prepayAfterSave(saasFormSaveDTO);
        } else if (Objects.equals(sheetTypeEnum, SheetTypeEnum.BAD_PAY)) {
            //坏账
            badAfterSave(saasFormSaveDTO);
        }
        //这里需要重置采购退货单里面的付款单信息
        Long returnedPurchaseId = saasFormSaveDTO.getReturnedPurchaseId();
        if (returnedPurchaseId != null) {
            saasRefundHelper.updateReturnedPurchasePaySheetId(returnedPurchaseId, newPaasFormDataEntity, saasFormSaveDTO.getCorpid());
        }
    }

    /**
     * 工作流付款单团队保存
     *
     * @param saasFormSaveDTO
     */
    @Override
    public void afterSaveForWorkflow(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        PayPlanSheetEntityExt payPlanSheetEntityExt = new PayPlanSheetEntityExt();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        BeanUtil.copyProperties(newPaasFormDataEntity, payPlanSheetEntityExt);
        operateSheetTeam(payPlanSheetEntityExt, new ArrayList<>(), true, newPaasFormDataEntity, saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), saasFormSaveDTO.getIsImport(), true);

    }
    /**
     * 操作付款单团队
     *
     * @param payPlanSheetEntityExt
     * @param sheetList
     * @param ignoreMainSheet
     * @param paasFormDataEntity
     * @param saasNeedRedundantAttrPojo
     * @param isImport
     */
    @Override
    public AfterSavePojo operateSheetTeam(PayPlanSheetEntityExt payPlanSheetEntityExt, List<PayPlanSheetEntityExt> sheetList,
                                          boolean ignoreMainSheet, PaasFormDataEntity paasFormDataEntity, SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo, Integer isImport, Boolean workFlowTag) throws XbbException {
        if (ignoreMainSheet) {
            sheetList.add(payPlanSheetEntityExt);
        }
        Map<Long, List<Long>> sheetIdAndDataIdMap = new HashMap<>(sheetList.size());
        List<Long> contractIdIn = new ArrayList<>();
        String attrCon = PaySheetEnum.LINK_PURCHASE.getAttr();
        for (PayPlanSheetEntityExt payPlanSheetEntityExtSen : sheetList){
            fundHelp.handleSheetIdAndContractIdMap(contractIdIn, sheetIdAndDataIdMap, payPlanSheetEntityExtSen, attrCon);
        }
        AfterSavePojo afterSavePojo = teamDataHelp.savePayOrPaymentSheetUserTeam(saasNeedRedundantAttrPojo, paasFormDataEntity, isImport,
                 null, sheetList, workFlowTag, false);
        return afterSavePojo;
    }

    @Override
    public void afterSaveForUpdateWorkflow(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(),saasFormSaveDTO.getNewPaasFormDataEntity().getId(), newPaasFormDataEntity,saasFormSaveDTO.getIsImport(),true);
    }


    /**
     * 坏账类型付款单普通流程保存之后需要做的操作
     *
     * @param saasFormSaveDTO
     */
    private void badAfterSave(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        Integer businessType = saasFormSaveDTO.getBusinessType();
        String corpid = saasFormSaveDTO.getCorpid();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        PayPlanSheetEntityExt payPlanSheetEntityExt = new PayPlanSheetEntityExt();
        BeanUtil.copyProperties(newPaasFormDataEntity, payPlanSheetEntityExt);
        JSONObject dataList = newPaasFormDataEntity.getData();
        PaySheetTypeEnum paySheetTypeEnum = PaySheetTypeEnum.getByBusinessType(businessType);
        SheetTypeEnum sheetTypeEnum = paySheetTypeEnum.getSheetTypeEnum();
        SheetAttrPojo sheetAttrPojo = new SheetAttrPojo(sheetTypeEnum.getXbbRefTypeEnum());
        List<PayPlanSheetEntityExt> sonSheetList = null;
        JSONArray amountDetails = saasFormSaveDTO.getAmountDetail();
        double allAmount = 0D;
        //付款计划和合同对应的付款金额
        Map<Long, Double> contractIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> paymentIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> contractIds = new HashSet<>();
        Set<Long> paymentIds = new HashSet<>();
        //付款单的实际坏账金额
        Double sheetAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.AMOUNT.getAttr(), 0D);

        //处理金额明细
        List<JSONObject> sonSheetDataList = saasSaveHelper.handleAmountDetail(saasFormSaveDTO, sheetAmount, sheetTypeEnum, sheetAttrPojo, dataList, amountDetails, allAmount, contractIdToAmount, paymentIdToAmount, contractIds, paymentIds);
        //处理付款计划并封装要更新的结果
        List<UpdateDataEntity> updatePayList = saasPayPlanHelper.handlePlan(sheetTypeEnum, dataList, corpid, paymentIdToAmount, paymentIds);
        //处理采购合同并封装要更新的结果
        List<UpdateDataEntity> updateConList = purchaseHelp.handleContract(sheetTypeEnum, corpid, contractIdToAmount, contractIds);
        //插入付款单、子付款单
        sonSheetList = saasPaySheetHelper.saveSheetSon(corpid, sonSheetDataList, payPlanSheetEntityExt, payPlanSheetEntityExt.getUuid());
        //更新付款计划/合同
        saasPayPlanHelper.savePayPlan(corpid, updatePayList, "PayPlanSheetServiceImpl.badSave：新建坏账付款单更新付款计划时失败");
        purchaseHelp.savePurchase(corpid, updateConList, "PayPlanSheetServiceImpl.badSave：新建坏账付款单更新合同时失败");
        //处理付款单团队
        operateSheetTeam(payPlanSheetEntityExt, sonSheetList, true, newPaasFormDataEntity, saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), saasFormSaveDTO.getIsImport(), false);
        //saasPaySheetHelper.handleSheetTeam(dataList, corpid, sheetTypeEnum, payPlanSheetEntityExt, sonSheetList, true);
        // 推送消息
        PaymentSheetSaveDTO payPlanSheetInsertDTO = new PaymentSheetSaveDTO();
        BeanUtil.copyProperties(saasFormSaveDTO, payPlanSheetInsertDTO);
        sheetAddMessage(payPlanSheetInsertDTO, PushTypeEnum.PAY_SHEET_BAD_ADD, dataList, corpid, payPlanSheetEntityExt, I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_BAD_ADD_TITLE), I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_BAD_ADD_CONTENT));

    }

    /**
     * 预付款、红冲预付款余额付款单普通流程保存之后需要做的操作
     *
     * @param saasFormSaveDTO
     */
    private void prepayAfterSave(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        Integer businessType = saasFormSaveDTO.getBusinessType();
        JSONObject dataList = newPaasFormDataEntity.getData();
        String corpid = saasFormSaveDTO.getCorpid();
        Long supplierId = dataList.getLong(PaySheetEnum.LINK_SUPPLIER.getAttr());
        boolean redFlag = false;
        PaySheetTypeEnum paySheetTypeEnum = PaySheetTypeEnum.getByBusinessType(businessType);
        SheetTypeEnum sheetTypeEnum = paySheetTypeEnum.getSheetTypeEnum();
        if (Objects.equals(sheetTypeEnum, SheetTypeEnum.RED_PREPAY)) {
            redFlag = true;
        }
        PayPlanSheetEntityExt payPlanSheetEntityExt = new PayPlanSheetEntityExt();
        BeanUtil.copyProperties(newPaasFormDataEntity, payPlanSheetEntityExt);
        //添加预付款余额
        saasPaySheetHelper.saveBySheet(payPlanSheetEntityExt);
        Map<String, FieldAttrEntity> explainMap = saasFormSaveDTO.getExplainMap();
        Double amount = FastJsonHelper.getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.AMOUNT.getAttr(), 0D);
        Long accountId = FastJsonHelper.getLongOrDefaultFromFormData(dataList, PaySheetEnum.FUND_ACCOUNT.getAttr(), 0L);
        Long addTime = payPlanSheetEntityExt.getAddTime();
        Long sheetTime = fundHelp.getSheetTime4FundFlow(dataList, PaySheetEnum.REAL_PAY_TIME.getAttr(), explainMap, addTime);
        amount = Arith.mul(amount, -1);
        payAndPaymentSheetHelp.saveByPaymentSheetOrPaySheet(accountId, amount, corpid);
        //流水表日志记录
        FundAccountFlowEntity fundAccountFlowEntity = new FundAccountFlowEntity(corpid, DateTimeUtil.getInt(), payPlanSheetEntityExt.getCreatorId(), FundAccountFlowTypeEnum.PAY_SHEET.getCode(), payPlanSheetEntityExt.getId(), accountId, sheetTime, amount);
        fundAccountFlowModel.insert(fundAccountFlowEntity);
        //处理付款单
        Map<Long, List<Long>> sheetIdAndDataIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> contractIdIn = new ArrayList<>();
        fundHelp.handleSheetIdAndCusIdMap(contractIdIn, sheetIdAndDataIdMap, payPlanSheetEntityExt, PaySheetEnum.LINK_SUPPLIER.getAttr());
        operateSheetTeam(payPlanSheetEntityExt, new ArrayList<>(), true, newPaasFormDataEntity, saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), saasFormSaveDTO.getIsImport(), false);
        //userTeamService.createPaySheetUser(corpid, supplierId, contractIdIn, sheetIdAndDataIdMap, sheetTypeEnum, false);
        // 添加推送消息
        PayPlanSheetInsertDTO payPlanSheetInsertDTO = new PayPlanSheetInsertDTO();
        BeanUtil.copyProperties(saasFormSaveDTO, payPlanSheetInsertDTO);
        PushTypeEnum pushTypeEnum;
        String pushTitle;
        String pushContent;
        if (redFlag) {
            pushTypeEnum = PushTypeEnum.PAY_SHEET_RED_PREPAY_ADD;
            pushTitle = I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_RED_PREPAY_ADD_TITLE);
            pushContent = I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_RED_PREPAY_ADD_CONTENT);
        } else {
            pushTypeEnum = PushTypeEnum.PAY_SHEET_PREPAY_ADD;
            pushTitle = I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_PREPAY_ADD_TITLE);
            pushContent = I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_PREPAY_ADD_CONTENT);
        }
        sheetAddMessage(payPlanSheetInsertDTO, pushTypeEnum, dataList, corpid, payPlanSheetEntityExt, pushTitle, pushContent);
    }

    /**
     * 红冲已核销、红冲预付款核销付款单普通流程保存之后需要做的操作
     *
     * @param saasFormSaveDTO
     */
    private void redAfterSave(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        Integer businessType = saasFormSaveDTO.getBusinessType();
        String corpid = saasFormSaveDTO.getCorpid();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        PayPlanSheetEntityExt payPlanSheetEntityExt = new PayPlanSheetEntityExt();
        BeanUtil.copyProperties(newPaasFormDataEntity, payPlanSheetEntityExt);
        JSONObject dataList = newPaasFormDataEntity.getData();
        PaySheetTypeEnum paySheetTypeEnum = PaySheetTypeEnum.getByBusinessType(businessType);
        SheetTypeEnum sheetTypeEnum = paySheetTypeEnum.getSheetTypeEnum();
        SheetAttrPojo sheetAttrPojo = new SheetAttrPojo(sheetTypeEnum.getXbbRefTypeEnum());
        List<PayPlanSheetEntityExt> sonSheetList = null;
        double allAmount = 0D;
        Map<String, FieldAttrEntity> explainMap = saasFormSaveDTO.getExplainMap();
        //付款计划和采购合同对应的付款金额
        Map<Long, Double> contractIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> paymentIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> contractIds = new HashSet<>();
        Set<Long> paymentIds = new HashSet<>();

        //处理金额明细
        Double sheetAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.AMOUNT.getAttr(), 0D);
        Double amount = Arith.mul(sheetAmount, -1);
        List<JSONObject> sonSheetDataList = saasSaveHelper.handleAmountDetail(saasFormSaveDTO, amount, sheetTypeEnum, sheetAttrPojo, dataList, saasFormSaveDTO.getAmountDetail(), allAmount, contractIdToAmount, paymentIdToAmount, contractIds, paymentIds);
        //处理付款计划
        List<UpdateDataEntity> updatePayList = saasPayPlanHelper.handlePlan(sheetTypeEnum, dataList, corpid, paymentIdToAmount, paymentIds);
        //处理采购合同
        List<UpdateDataEntity> updateConList = purchaseHelp.handleContract(sheetTypeEnum, corpid, contractIdToAmount, contractIds);
        //插入付款单、子付款单
        sonSheetList = saasPaySheetHelper.saveSheetSon(corpid, sonSheetDataList, payPlanSheetEntityExt, payPlanSheetEntityExt.getUuid());
        //更新付款计划/合同
        saasPayPlanHelper.savePayPlan(corpid, updatePayList, "PayPlanSheetServiceImpl.redSave：新建红冲付款单更新付款计划时失败");
        purchaseHelp.savePurchase(corpid, updateConList, "PayPlanSheetServiceImpl.redSave：新建红冲付款单更新采购合同时失败");
        Long accountId = FastJsonHelper.getLongOrDefaultFromFormData(dataList, PaySheetEnum.FUND_ACCOUNT.getAttr(), 0L);
        Long addTime = payPlanSheetEntityExt.getAddTime();
        Long sheetTime = fundHelp.getSheetTime4FundFlow(dataList, PaySheetEnum.REAL_PAY_TIME.getAttr(), explainMap, addTime);
        //账户余额变动 红冲金额未处理成负数
        payAndPaymentSheetHelp.saveByPaymentSheetOrPaySheet(accountId, amount, corpid);
        //流水表日志记录
        FundAccountFlowEntity fundAccountFlowEntity = new FundAccountFlowEntity(corpid, DateTimeUtil.getInt(), payPlanSheetEntityExt.getCreatorId(), FundAccountFlowTypeEnum.PAY_SHEET.getCode(), payPlanSheetEntityExt.getId(), accountId, sheetTime, amount);
        fundAccountFlowModel.insert(fundAccountFlowEntity);
        //处理付款单团队-必须在团队保存后执行，需要用到付款单的id
        operateSheetTeam(payPlanSheetEntityExt, sonSheetList, true, newPaasFormDataEntity, saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), saasFormSaveDTO.getIsImport(), false);
        //saasPaySheetHelper.handleSheetTeam(dataList, corpid, sheetTypeEnum, payPlanSheetEntityExt, sonSheetList, true);
        // 添加推送消息
        PaymentSheetSaveDTO payPlanSheetInsertDTO = new PaymentSheetSaveDTO();
        BeanUtil.copyProperties(saasFormSaveDTO, payPlanSheetInsertDTO);
        sheetAddMessage(payPlanSheetInsertDTO, PushTypeEnum.PAY_SHEET_RED_ADD, dataList, corpid, payPlanSheetEntityExt, I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_RED_ADD_TITLE), I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_RED_ADD_CONTENT));
    }

    /**
     * 已核销、预收款核销付款单普通流程保存之后需要做的操作
     *
     * @param saasFormSaveDTO
     */
    private void writeOffAfterSave(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        Integer businessType = saasFormSaveDTO.getBusinessType();
        String corpid = saasFormSaveDTO.getCorpid();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        PayPlanSheetEntityExt payPlanSheetEntityExt = new PayPlanSheetEntityExt();
        BeanUtil.copyProperties(newPaasFormDataEntity, payPlanSheetEntityExt);
        JSONObject newData = newPaasFormDataEntity.getData();
        PaySheetTypeEnum paySheetTypeEnum = PaySheetTypeEnum.getByBusinessType(businessType);
        SheetTypeEnum sheetTypeEnum = paySheetTypeEnum.getSheetTypeEnum();
        SheetAttrPojo sheetAttrPojo = new SheetAttrPojo(XbbRefTypeEnum.PAY_SHEET);
        Map<String, FieldAttrEntity> explainMap = saasFormSaveDTO.getExplainMap();
        //付款计划和采购合同对应的付款金额
        Map<Long, Double> contractIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> paymentIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> contractIds = new HashSet<>();
        Set<Long> paymentIds = new HashSet<>();
        List<PayPlanSheetEntityExt> sonSheetList = null;
        //回/付款单的实付回/付款金额
        Double sheetAmount;
        double allAmount = 0D;
        boolean writeOffPrepaymentFlag = SheetTypeEnum.isWriteOffPre(sheetTypeEnum);
        if (writeOffPrepaymentFlag) {
            //预付/付款核销，是用的核销金额
            sheetAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(newData, sheetAttrPojo.getAttrWriteOffAmount(), 0D);
        } else {
            sheetAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(newData, sheetAttrPojo.getAttrAmount(), 0D);
        }
        //处理付款单金额明细
        List<JSONObject> sonSheetDataList = saasSaveHelper.handleAmountDetail(saasFormSaveDTO, sheetAmount, sheetTypeEnum, sheetAttrPojo, newData, saasFormSaveDTO.getAmountDetail(),
                allAmount, contractIdToAmount, paymentIdToAmount, contractIds, paymentIds);
        //处理付款计划并封装要更新的结果：并把付款计划的已付金额增加及更改其付款状态等
        List<UpdateDataEntity> updatePayList = saasPayPlanHelper.handlePlan(sheetTypeEnum, newData, corpid, paymentIdToAmount, paymentIds);
        //处理采购合同并封装要更新的结果：并把采购合同的已付金额增加等
        List<UpdateDataEntity> updateConList = purchaseHelp.handleContract(sheetTypeEnum, corpid, contractIdToAmount, contractIds);
        //插入付款单以及子付款单
        sonSheetList = saasPaySheetHelper.saveSheetSon(corpid, sonSheetDataList, payPlanSheetEntityExt, payPlanSheetEntityExt.getUuid());
        //更新付款计划/合同
        saasPayPlanHelper.savePayPlan(corpid, updatePayList, "PayPlanSheetServiceImpl.writeOffSave：新建已核销付款单更新付款计划时失败");
        purchaseHelp.savePurchase(corpid, updateConList, "PayPlanSheetServiceImpl.writeOffSave：新建已核销付款单更新采购合同时失败");
        if (writeOffPrepaymentFlag) {
            //核销预付款付款单新建时，减少预付款余额
            saasPaySheetHelper.saveBySheet(payPlanSheetEntityExt);
        } else {
            Long addTime = payPlanSheetEntityExt.getAddTime();
            Long accountId = FastJsonHelper.getLongOrDefaultFromFormData(newData, PaySheetEnum.FUND_ACCOUNT.getAttr(), 0L);
            Long sheetTime = fundHelp.getSheetTime4FundFlow(newData, PaySheetEnum.REAL_PAY_TIME.getAttr(), explainMap, addTime);
            //账户余额变动 付款取反
            sheetAmount = Arith.mul(sheetAmount, -1);
            payAndPaymentSheetHelp.saveByPaymentSheetOrPaySheet(accountId, sheetAmount, corpid);
            //流水表日志记录
            FundAccountFlowEntity fundAccountFlowEntity = new FundAccountFlowEntity(corpid, addTime, payPlanSheetEntityExt.getCreatorId(), FundAccountFlowTypeEnum.PAY_SHEET.getCode(), payPlanSheetEntityExt.getId(), accountId, sheetTime, sheetAmount);
            fundAccountFlowModel.insert(fundAccountFlowEntity);
        }
        //处理付款单团队-必须在团队保存后执行，需要用到付款单的id
        operateSheetTeam(payPlanSheetEntityExt, sonSheetList, true, newPaasFormDataEntity, saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), saasFormSaveDTO.getIsImport(), false);
        //saasPaySheetHelper.handleSheetTeam(newData, corpid, sheetTypeEnum, payPlanSheetEntityExt, sonSheetList, true);
        // 添加推送消息
        PaymentSheetSaveDTO payPlanSheetInsertDTO = new PaymentSheetSaveDTO();
        BeanUtil.copyProperties(saasFormSaveDTO, payPlanSheetInsertDTO);
        sheetAddMessage(payPlanSheetInsertDTO, PushTypeEnum.PAY_SHEET_ADD, newData, corpid, payPlanSheetEntityExt, I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_ADD_TITLE), I18nMessageUtil.getMessage(PayPlanPushConstant.PAY_SHEET_ADD_CONTENT));
    }

    /**
     * 处理others字段
     *
     * @param data paymentSheet数据
     * @return com.alibaba.fastjson.JSONObject
     * @throws XbbException 异常
     * @author 徐俊杰
     * @date 2019/11/21 9:29
     * @since v1.0
     */
    private JSONObject disposePaySheetOthers(JSONObject data) throws XbbException {
        JSONObject others = new JSONObject();
        //内部展示的是文字
        String status = commonHelp.formatFundStatusText(data, PaySheetEnum.PAY_SHEET_TYPE.getAttr(),PaySheetTypeEnum.UNKNOWN.getName());
        //文字转为code
        String type = PaySheetTypeEnum.getByName(status).getCode();
        String amount = FundHelp.getSheetAmount4PaySheet(data, type) + UnitEnum.MONEY.getName();
        others.put("amount", amount);
        others.put("status", status);
        //处理红冲和坏账状态
        boolean red = PaySheetTypeEnum.isRed(type);
        int redStatus = red ? 1 : 0;
        boolean bad = PaySheetTypeEnum.isBad(type);
        int badStatus = bad ? 1 : 0;
        others.put("isRed", redStatus);
        others.put("isBad", badStatus);
        return others;
    }

    /**
     * 删除付款单
     * @param payPlanSheetDeleteBatchDTO 删除入参dto
     * @param payPlanSheetDeleteBatchVO 删除返回vo
     * @param sheetList 要删除的付款单（此list只包含无父子的付款单，父付款单）
     * @param corpid 公司id
     * @param singleFlag 是否是单个删除
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void deletePaySheet(PayPlanSheetDeleteBatchDTO payPlanSheetDeleteBatchDTO, PayPlanSheetDeleteBatchVO payPlanSheetDeleteBatchVO, List<PaasFormDataEntityExt> sheetList, String corpid, Integer singleFlag) throws XbbException {
        //删除的回款单编号list（用于记录日志，如果有删除失败的情况，则需要移除部分回款单编号）
        List<String> delNoList= new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        String attrSheetType = PaySheetEnum.getAttrConnectData(PaySheetEnum.PAY_SHEET_TYPE);
        String attrOrigin = PaySheetEnum.getAttrConnectData(PaySheetEnum.ORIGIN_ID);
        List<String> redCodeList = PaySheetTypeEnum.getRedCodeList();
        //查询出关联的红冲付款单并塞入sheetList内
        formHelp.getLinkRedSheetList(corpid, sheetList, IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, attrSheetType, attrOrigin, redCodeList);
        List<String> errorDataList = new ArrayList<>();
        Set<String> errorDataSet = new HashSet<>();
        Set<String> errorTypeSet = new HashSet<>();
        List<String> errorTypeList = new ArrayList<>();
        Set<Long> allCustomerIdSet = new HashSet<>();
        //供应商id-该供应商对应的预付款类型付款单编号（id）list：只有预付款类型删除是对供应商余额减少，此时需要判断供应商余额是否充足，不足则该供应商下的预付款类型付款单不让删除
        Map<Long, List<String>> prepaymentNoMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, List<Long>> prepaymentIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //父子单据相同的uuid - 该uuid对应的父单及其所有子单
        Map<String, List<Long>> uuidSheetMap = new HashMap<>(sheetList.size());
        //采购合同id-该采购合同下的所有付款单id、编号集合（注意：不能单单用子付款单去构建关系map，因为父的付款单也要构建到关系内）
        Map<Long, List<Long>> cidSheetIdListMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, List<String>> cidSheetNoListMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //付款计划id-该付款计划下的所有付款单id、编号集合（注意：不能单单用子付款单去构建关系map，因为父的付款单也要构建到关系内）
        Map<Long, List<Long>> pidSheetIdListMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, List<String>> pidSheetNoListMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //资金账户ID-更改的金额
        Map<Long, Double> fundAccountNoListMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //所有要删除的付款单id list（无父子的回款单，父、子回款单）
        List<Long> allDelIdList = new ArrayList<>();
        //更新关联采购合同、付款单计划的updateRelateList只包含了无父子付款单、子付款单，不包含父付款单。因为有父子付款单时更新关联业务，要依赖于明细（明细即子付款单，无明细的则依赖本身），因为父的会关联多个相同业务，如关联多个采购合同
        List<PaasFormDataEntityExt> updateRelateList = new ArrayList<>();
        Set<String> paymentSheetUuids = new HashSet<>();
        //付款单id-付款金额（预付款核销要读取核销金额）
        Map<Long, Double> sheetIdToAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //2020/5/15 两个合同创建合并回款单 回款单开票,删除回款单 回款单被删除(原因:校验是否有发票的时候没有移除掉父回款单) 这构建父回款单uuid map
        Map<String,Long> parentPaySheetMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,String> parentSerialNo = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (PaasFormDataEntityExt entityExt : sheetList) {
            Integer flowStatus = entityExt.getFlowStatus();
            String serialNo = entityExt.getSerialNo();
            if (Objects.equals(FlowStatusEnum.APPROVAL_PENDING.getType(), flowStatus) || Objects.equals(FlowStatusEnum.IN_APPROVAL.getType(), flowStatus)) {
                // 待审批和审批中数据不允许删除
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208056, PaymentErrorCodeEnum.API_ERROR_208056.getMsg(), serialNo);
            }
            JSONObject data = entityExt.getData();
            Long customerId = FastJsonHelper.getLongOrDefaultFromFormData(data, PaySheetEnum.LINK_SUPPLIER.getAttr(), 0L);
            allCustomerIdSet.add(customerId);
            String sheetType = FastJsonHelper.getStringFromFormData(data, PaySheetEnum.PAY_SHEET_TYPE.getAttr());
            Double amount = FundHelp.getSheetAmount4PaySheet(data, sheetType);
            Long id = entityExt.getId();
            if (Objects.equals(sheetType, PaySheetTypeEnum.PREPAY.getCode())) {
                //预付款都没有明细
                List noList = prepaymentNoMap.getOrDefault(customerId, new ArrayList<>());
                noList.add(serialNo);
                List<Long> idList = prepaymentIdMap.getOrDefault(customerId, new ArrayList<>());
                idList.add(id);
                prepaymentNoMap.put(customerId, noList);
                prepaymentIdMap.put(customerId, idList);
            }
            sheetIdToAmount.put(id, amount);
            allDelIdList.add(id);
            delNoList.add(entityExt.getSerialNo());
            String uuid = entityExt.getUuid();
            if(Objects.equals(entityExt.getAlone(),SheetAloneEnum.NORMAL.getCode())){
                parentPaySheetMap.put(uuid,entityExt.getId());
                parentSerialNo.put(entityExt.getId(),entityExt.getSerialNo());
            }
            if (Objects.equals(entityExt.getAlone(), SheetAloneEnum.PARENT.getCode())) {
                //alone=父code，不需要更新关联采购合同、付款计划。但其有子付款单：需通过该父单的uuid读取子付款单list
                paymentSheetUuids.add(uuid);
                parentPaySheetMap.put(uuid,entityExt.getId());
                parentSerialNo.put(entityExt.getId(),entityExt.getSerialNo());
                commonHelp.handleIdDataIdNoListMap(cidSheetIdListMap, cidSheetNoListMap, data, entityExt, PaySheetEnum.LINK_PURCHASE.getAttr());
                commonHelp.handleIdDataIdNoListMap(pidSheetIdListMap, pidSheetNoListMap, data, entityExt, PaySheetEnum.PAY_PLAN.getAttr());
                List<Long> collectList = uuidSheetMap.getOrDefault(uuid, new ArrayList<>());
                collectList.add(entityExt.getId());
                uuidSheetMap.put(uuid, collectList);
            } else {
                updateRelateList.add(entityExt);
            }
        }
        Set<Long> inApprovalIdInvoiceList = new HashSet<>();
        if (commonHelp.isOpenWorkFlow(corpid)) {
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
            boolQueryBuilder.filter(termsQuery(PurchaseInvoiceEnum.getEsAttr4Keyword(PurchaseInvoiceEnum.PAY_SHEET_ID), allDelIdList));
            boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType())));
            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_PURCHASE_INVOICE.getType()));
            List<PaasFormDataEntityExt> purchaseInvoiceFormDataList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PURCHASE_INVOICE,
                    boolQueryBuilder, PaasFormDataEntityExt.class, Arrays.asList(PurchaseInvoiceEnum.getAttrConnectData(PurchaseInvoiceEnum.PAY_SHEET_ID), FieldTypeEnum.DATAID.getAlias()));
            for (PaasFormDataEntityExt paasProcessDataEntity : purchaseInvoiceFormDataList) {
                JSONArray paymentSheetArr = paasProcessDataEntity.getData().getJSONArray(PurchaseInvoiceEnum.PAY_SHEET_ID.getAttr());
                paymentSheetArr.forEach(item -> {
                    inApprovalIdInvoiceList.add(Long.valueOf(item.toString()));
                });
            }
        } else {
            List<PaasProcessDataEntity> processInvoiceDataEntityList = paasProcessDataModel.getInvoiceInApprovalDataByIdConditionJsonArray(XbbRefTypeEnum.PURCHASE_INVOICE.getCode(), PurchaseInvoiceEnum.PAY_SHEET_ID.getAttr(), allDelIdList, corpid, Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType()));
            for (PaasProcessDataEntity paasProcessDataEntity : processInvoiceDataEntityList) {
                JSONArray paymentSheetArr = JSONObject.parseObject(paasProcessDataEntity.getData()).getJSONArray(PurchaseInvoiceEnum.PAY_SHEET_ID.getAttr());
                paymentSheetArr.forEach(item -> {
                    inApprovalIdInvoiceList.add(Long.valueOf(item.toString()));
                });
            }
        }
        List<PaasFormDataEntityExt> removeList = new ArrayList<>();
        for (PaasFormDataEntityExt paasFormDataEntityExt : sheetList) {
            if (inApprovalIdInvoiceList.contains(paasFormDataEntityExt.getId())) {
                if(!errorTypeList.contains(InvoiceErrorCodeEnum.API_ERROR_216035.getMsg())){
                    errorTypeList.add(InvoiceErrorCodeEnum.API_ERROR_216035.getMsg());
                }
                errorDataList.add(paasFormDataEntityExt.getSerialNo());
                removeList.add(paasFormDataEntityExt);
                if(CollectionsUtil.isNotEmpty(allDelIdList)) {
                    allDelIdList.remove(paasFormDataEntityExt.getId());
                }
                if(CollectionsUtil.isNotEmpty(delNoList)){
                    delNoList.remove(paasFormDataEntityExt.getSerialNo());
                }
            }
        }
        if(CollectionsUtil.isNotEmpty(removeList) && CollectionsUtil.isNotEmpty(sheetList)){
            sheetList.removeAll(removeList);
        }
        if (allDelIdList.size() > 0) {
            //采购退货，不需要依赖子付款单
            returnedPurchaseService.updateRefund4Del(corpid, allDelIdList, sheetIdToAmount);
        }
        //要同步处理的子付款单list
        List<PaasFormDataEntityExt> childEntityExtList = fundHelp.getChildEsDataListByParentUuids(XbbRefTypeEnum.PAY_SHEET,corpid, paymentSheetUuids, null, null);
        //构建子回款单map
        Map<Long,String> subPaySheetMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String,List<Long>> uuidSubPaySheetMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String,List<String>> subPaySheetSerailNo = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (PaasFormDataEntityExt child : childEntityExtList) {
            allDelIdList.add(child.getId());
            subPaySheetMap.put(child.getId(),child.getUuid());
            saasSaveHelp.addMapTwoId(uuidSubPaySheetMap,child.getUuid(),child.getId());
            saasSaveHelp.addMapTwoSerialNo(subPaySheetSerailNo,child.getUuid(),child.getSerialNo());
            String uuid = child.getUuid();
            List<Long> collectList = uuidSheetMap.getOrDefault(uuid, new ArrayList<>());
            collectList.add(child.getId());
            uuidSheetMap.put(uuid, collectList);
        }
        updateRelateList.addAll(childEntityExtList);
        //判断这些付款单（发票管理的子付款单）下面是否存在发票：该校验要在更新供应商余额、采购合同/付款计划的未付、已付、坏账等之前处理
        purchaseInvoiceService.checkBusinessDeleteHaveInvoice(allDelIdList,corpid,XbbRefTypeEnum.PAY_SHEET,errorTypeList,errorDataList,null,delNoList,parentPaySheetMap,parentSerialNo,subPaySheetMap,uuidSubPaySheetMap,subPaySheetSerailNo);
        //只包含了无父子付款单、子付款单，不包含父付款单
        int sizeUpdate = updateRelateList.size();
        SheetAttrPojo sheetAttrPojo = new SheetAttrPojo(XbbRefTypeEnum.PAY_SHEET);
        SheetDeleteHandleRelateDTO sheetDeleteHandleRelateDTO = new SheetDeleteHandleRelateDTO(sizeUpdate, sheetAttrPojo, delNoList, uuidSheetMap, cidSheetIdListMap, cidSheetNoListMap, pidSheetIdListMap, pidSheetNoListMap);
        Iterator<PaasFormDataEntityExt> iterator = updateRelateList.iterator();
        while (iterator.hasNext()) {
            PaasFormDataEntityExt entityExt = iterator.next();
            if (allDelIdList.contains(entityExt.getId())) {
                commonHelp.setPaymentSheetDeleteHandleRelateDTO(sheetAttrPojo, entityExt, sheetDeleteHandleRelateDTO);
            } else {
                //未通过发票校验：付款单下有关联发票，不能删除付款单
                iterator.remove();
            }
        }
        List<Long> paymentIdIn = new ArrayList<>();
        List<Long> contractIdIn = new ArrayList<>();
        try {
            if (allCustomerIdSet.size() > 0) {
                payBalanceService.updatePayBalance4Del(corpid, errorTypeSet, errorDataSet, allCustomerIdSet, prepaymentNoMap, prepaymentIdMap, allDelIdList, sheetDeleteHandleRelateDTO);
            }
            Set<Long> contractIds = sheetDeleteHandleRelateDTO.getContractIds();
            Set<Long> paymentIds = sheetDeleteHandleRelateDTO.getPaymentIds();
            List<UpdateDataEntity> updatePlanList = new ArrayList<>();
            if (paymentIds.size() > 0) {
                //先处理是否能删除：校验删除后已付、未付、坏账值是否为负
                updatePlanList = payPlanService.updatePlan4Del(corpid, errorTypeSet, errorDataSet, allDelIdList, sheetDeleteHandleRelateDTO);
                paymentIdIn.addAll(paymentIds);
            }
            List<UpdateDataEntity> updateContractList = new ArrayList<>();
            if (contractIds.size() > 0) {
                //先处理是否能删除：校验删除后已付、未付、坏账值是否为负
                updateContractList = purchaseService.updateContract4Del(corpid, errorTypeSet, errorDataSet, allDelIdList, sheetDeleteHandleRelateDTO);
                contractIdIn.addAll(contractIds);
            }
            if (allDelIdList.size() > 0){
                if (BasicConstant.ONE.equals(singleFlag) && BasicConstant.ONE.equals(sizeUpdate)) {
                    payPlanSheetModel.deleteByKey(allDelIdList.get(0), corpid);
                } else {
                    payPlanSheetModel.deleteBatch(allDelIdList, corpid, DelEnum.DELETE.getDel());
                }
                payPlanSheetDeleteBatchVO.setDeleteIds(allDelIdList);
                //资金流水删除
                fundAccountFlowService.deleteBatch(allDelIdList, FundAccountFlowTypeEnum.PAY_SHEET.getCode(), corpid);
            }
            try {
                if (updatePlanList.size() > 0) {
                    payPlanModel.updateBatch(updatePlanList, corpid);
                }
                if (updateContractList.size() > 0) {
                    purchaseModel.updateBatch(updateContractList, corpid);
                }
            } catch (Exception e) {
                LOG.error("PayPlanSheetServiceImpl.deletePaySheet  关联更新采购合同/付款计划updatePlanList、updateContractList时报错", e);
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208048);
            }
            for (PaasFormDataEntityExt paasFormDataEntityExt : sheetList) {
                if (!allDelIdList.contains(paasFormDataEntityExt.getId())) {
                    continue;
                }
                //计算资金账户金额需要过滤无法被删除的付款单
                JSONObject data = paasFormDataEntityExt.getData();
                String sheetType = FastJsonHelper.getStringFromFormData(data, PaySheetEnum.PAY_SHEET_TYPE.getAttr());
                Double amount = fundHelp.getSheetAmount4PaySheet(data, sheetType);
                if (!Objects.equals(sheetType, PaySheetTypeEnum.BAD_PAY.getCode()) && !Objects.equals(sheetType, PaySheetTypeEnum.WRITE_OFF_PREPAY.getCode())) {
                    //资金账户余额处理
                    Long accountId = FastJsonHelper.getLongOrDefaultFromFormData(data, PaySheetEnum.FUND_ACCOUNT.getAttr(), 0L);
                    fundAccountNoListMap.merge(accountId, amount, Arith::add);
                }
            }
            if (fundAccountNoListMap.size() > 0) {
                fundAccountService.saveBatchByPaymentSheetOrPaySheet(fundAccountNoListMap);
            }
            errorDataList.addAll(errorDataSet);
            errorTypeList.addAll(errorTypeSet);
            payPlanSheetDeleteBatchVO.setErrorDataList(errorDataList);
            payPlanSheetDeleteBatchVO.setErrorTypeList(errorTypeList);
            payPlanSheetDeleteBatchVO.setErrorDataMemo(SaasDeleteHelp.getErrorDataMemo(errorTypeList, errorDataList));
            delLog(payPlanSheetDeleteBatchDTO, corpid, delNoList);
        } catch (XbbException e) {
            LOG.error("deletePaySheet rollback" + e);
            delRollBack4LinkEs(corpid, allDelIdList, paymentIdIn, contractIdIn, allCustomerIdSet);
            throw e;
        } catch (Exception e) {
            LOG.error("deletePaySheet rollback" + e);
            delRollBack4LinkEs(corpid, allDelIdList, paymentIdIn, contractIdIn, allCustomerIdSet);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    /**
     * 生成删除付款单日志
     * @param payPlanSheetDeleteBatchDTO
     * @param corpid
     * @param delNoList
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void delLog(PayPlanSheetDeleteBatchDTO payPlanSheetDeleteBatchDTO, String corpid, List<String> delNoList) throws XbbException {
        int size = delNoList.size();
        if (size > BasicConstant.ZERO) {
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.DELETE;
            if (Objects.equals(BasicConstant.ONE, payPlanSheetDeleteBatchDTO.getIsBusinessRule())) {
                operateTypeEnum = OperateTypeEnum.RULE_DELETE;
            }
            //生成删除日志(区分单个删除和批量删除)
            String userId = payPlanSheetDeleteBatchDTO.getUserId();
            String userName = payPlanSheetDeleteBatchDTO.getLoginUserName();
            String nameStr = StringUtils.join(delNoList, "，");
            if(size > BasicConstant.ONE){
                String memo = format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_BATCH_DELETE_FORM_DETAIL), userName, XbbRefTypeEnum.PAY_SHEET.getName(), size);
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(PaySheetEnum.PAY_PLAN_NO.getAttrName());
                infoArrPojo.setContent(nameStr);
                infoArrPojoList.add(infoArrPojo);
                mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, userName, OperateModuleTypeEnum.PayManage, operateTypeEnum,
                        "", "", memo, payPlanSheetDeleteBatchDTO.getHttpHeader());
            } else if (Objects.equals(size, BasicConstant.ONE)){
                String memo = format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_DELETE_WORK), userName, XbbRefTypeEnum.PAY_SHEET.getName(), nameStr);
                mongoLogHelp.buildLog(corpid, userId, userName, OperateModuleTypeEnum.PayManage, operateTypeEnum,
                        delNoList.toString(), nameStr, memo, payPlanSheetDeleteBatchDTO.getHttpHeader());
            }
        }
    }

    /**
     * 处理付款单团队
     * @param dataList 付款单data
     * @param corpid 公司id
     * @param sheetTypeEnum
     * @param planSheetEntityExt 父付款单
     * @param sheetList 要处理团队的付款单list
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void handleSheetTeam(JSONObject dataList, String corpid, SheetTypeEnum sheetTypeEnum, PayPlanSheetEntityExt planSheetEntityExt, List<PayPlanSheetEntityExt> sheetList) throws XbbException {
        sheetList.add(planSheetEntityExt);
        Long supplierId = dataList.getLong(PaySheetEnum.LINK_SUPPLIER.getAttr());
        Map<Long, List<Long>> sheetIdAndDataIdMap = new HashMap<>(sheetList.size());
        List<Long> contractIdIn = new ArrayList<>();
        String attrCon = PaySheetEnum.LINK_PURCHASE.getAttr();
        for (PayPlanSheetEntityExt entityExt : sheetList){
            fundHelp.handleSheetIdAndContractIdMap(contractIdIn, sheetIdAndDataIdMap, entityExt, attrCon);
        }
        userTeamService.createPaySheetUser(corpid, supplierId, contractIdIn, sheetIdAndDataIdMap, sheetTypeEnum, false);
    }
}
